<?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>christian.soronellas</title>
	<atom:link href="http://christian.soronellas.es/feed/" rel="self" type="application/rss+xml" />
	<link>http://christian.soronellas.es</link>
	<description>convention_over_configuration</description>
	<lastBuildDate>Sun, 16 Oct 2011 17:30:26 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Autoloading en Zend Framework</title>
		<link>http://christian.soronellas.es/2011/10/09/autoloading-en-zend-framework/</link>
		<comments>http://christian.soronellas.es/2011/10/09/autoloading-en-zend-framework/#comments</comments>
		<pubDate>Sun, 09 Oct 2011 10:45:22 +0000</pubDate>
		<dc:creator>Christian Soronellas</dc:creator>
				<category><![CDATA[Desarrollo web]]></category>
		<category><![CDATA[zend framework]]></category>

		<guid isPermaLink="false">http://christian.soronellas.es/?p=377</guid>
		<description><![CDATA[Últimamente en emagister, me encuentro dedicado entre otras cosas a ajustar el rendimiento del autoloading de clases en Zend Framework ya qué es una posible mejora que puede reportar un enorme ROI en impacto de negocio. De acuerdo, quizá no directamente en impacto de negocio pero sí de manera indirecta. Probablemente un sitio web que [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">Últimamente en emagister, me encuentro dedicado entre otras cosas a ajustar el rendimiento del <strong>autoloading de clases en Zend Framework</strong> ya qué es una posible mejora que puede reportar un enorme ROI en impacto de negocio. De acuerdo, quizá no directamente en impacto de negocio pero sí de manera indirecta. Probablemente un sitio web que pueda servir más páginas a más usuarios puede ver sensiblemente aumentado sus ratios de conversión. Y eso, creo que puede poner contentos a los chicos del área de negocio. Bien, empecemos.</p>
<h2>El componente Zend_Loader</h2>
<p style="text-align: justify;">Este quizá sea uno de los componentes más usados en todo el framework, ya que cómo su propio nombre indica es el encargado de toda la carga de clases. Pero una de las cosas que más me desagrada, ya no del componente sino del propio framework en sí, es la manera qué tiene de usarlo, pues algunos de sus subcomponentes (cómo el Zend_Loader_PluginLoader) son instanciados directamente por otras clases produciendo un pequeño acople que a veces resulta un poco molesto. Y más si te dedicas a investigar cómo mejorar precisamente este aspecto.</p>
<h3>Pros y contras de usar Zend_Loader</h3>
<p style="text-align: justify;">Por una parte, Zend_Loader es un componente muy cómodo para desarrollar sobretodo si estamos usando Zend_Loader_Autoloader. Tiene una integración perfecta con Zend_Controller_Front permitiendo la carga de clases automática dentro de módulos MVC, lo que cómo he dicho es muy cómodo pues el desarrollador ya no tiene que preocuparse de la carga de clases y puede centrarse en otros aspectos de la aplicación.</p>
<p style="text-align: justify;">Cómo contra, está la penalización en rendimiento que puede ocasionar el utilizar según que partes. Por ejemplo, usar <i>Zend_Loader::loadClass</i> tiene una fuerte penalización en rendimiento debido a que <strong>siempre</strong> tiene que calcular el path a la clase que se le está pidiendo. Cálculos cómo diferenciar un namespace de PHP 5.3 de un namespace de PEAR, comprobar que ciertos caracteres no aparezcan en el nombre de archivo, jugar con el include_path y finalmente incluir la clase. Por suerte este componente ya ha sido deprecado a partir de la versión 1.8 de <strong>Zend Framework</strong> y a partir de la versión 2.0 va a dejar de existir, además de que se desaconseja encarecidamente su uso en favor del componente <i>Zend_Loader_Autoloader</i>.</p>
<p style="text-align:justify;">Otro componente qué también penaliza bastante en rendimiento es el <i>Zend_Loader_PluginLoader</i>, es decir el responsable de la carga de plugins de Zend Framework y ampliamente usado (y acoplado :) por otros componentes. Este componente es capaz de registrar &#8220;prefijos&#8221; de classe y por cada uno de ellos asociarle uno o más paths donde puede existir el componente. El coding standards de Zend Framework dicta que los prefijos de clase sería todo el árbol de carpetas en el que se encuentra el componente separados por &#8220;_&#8221;. Así por ejemplo en el componente <i>Zend_View_Abstract</i> el prefijo de clase sería &#8220;Zend_View&#8221;. una vez visto esto y analizando un poco a fondo el componente <i>Zend_Loader_PluginLoader</i> se puede ver que al intentar cargar un plugin se recorre todos los prefijos de clases y sus paths asociados buscando un clase que encaje (por medio de <i>Zend_Loader::isReadable</i>, qué también penaliza). Por ejemplo para cargar el plugin (inventado) &#8220;Css&#8221; teniendo los prefijos registrados &#8220;Mi_Libreria_Personalizada&#8221; y &#8220;Zend_View_Helper&#8221; con 5 paths por cada prefijo, podría llegar a hacer 10 entradas en disco por cada petición HTTP.</p>
<h2>Tips para mejorar el autoloading en Zend Framework</h2>
<p style="text-align:justify;">Voy a hacer una breve síntesis de los métodos qué existen para mejorar la carga de clases y de plugins en Zend Framework. Todo este material se puede encontrar en el sitio web de Zend Framework y por Google, y aquí lo voy a agrupar un poco.</p>
<h3>Optimizar el include_path</h3>
<p style="text-align:justify;">Hay varias cosas que se pueden hacer para optimizar el include_path. En primer lugar, siempre usar paths absolutos o paths relativos a un path absoluto para hacer mayor uso de las directivas <i>realpath_cache_*</i>, ya que así no obligamos al intérprete de PHP a resolver el path relativo y además vamos a ganar algo en rendimiento ya que vamos a hacer que internamente PHP use el cache de paths absolutos.</p>
<pre>
&lt;?php
$paths = array(
  realpath(__DIR__ . &#039;/../library&#039;),
  &#039;.&#039;
);
set_include_path(implode(PATH_SEPARATOR, $paths));
</pre>
<p style="text-align:justify;">Además también podemos reducir el numero de paths dentro de include_path para reducir las posibilidades de búsqueda de clases, definir el path a Zend Framework lo antes posible en la lista de paths de include_path y/o no definir el directorio actual cómo directorio de búsqueda en include_path. Así que si aún no sigues estas reglas, ya lo sabes! ;)</p>
<h3>Eliminar require_once innecesarios</h3>
<p style="text-align:justify;">Las aplicaciones web actuales deberían todas hacer uso del autoloading de clases. Si aún no lo estás usando, plantéatelo pues es algo bastante necesario ya que unifica los procesos de carga de clases y ayuda a establecer un orden de directorios.</p>
<p style="text-align:justify;">Zend Framework por defecto en casi todas las definiciones de clase usa los <i>require_once</i>, y usando el componente <i>Zend_Loader_Autoloader</i> ya no son necesarios. Y no solo eso sino que de esta manera estamos usando <strong>lazy loading</strong> para la carga de clases lo que sin duda nos va a dar alguna mejora de rendimiento.</p>
<pre>
# Script para remover los "require_once" innecesarios en *nix
% cd path/to/ZendFramework/library
% find . -name '*.php' -not -wholename '*/Loader/Autoloader.php' \
-not -wholename '*/Application.php' -print0 | \
xargs -0 sed --regexp-extended --in-place 's/(require_once)/\/\/ \1/g'
</pre>
<pre>
# Script para remover los "require_once" innecesarios en mac (el sed no funciona exactamente igual)
% cd path/to/ZendFramework/library
% find . -name '*.php' -not -wholename '*/Loader/Autoloader.php' \
-not -wholename '*/Application.php' -print0 | \
xargs -0 sed -E -i '.bak' 's/(require_once)/\/\/ \1/g'
</pre>
<h3>Mejorar la velocidad del PluginLoader</h3>
<p style="text-align:justify;">Cómo ya he dicho antes, el PluginLoader es un componente que permite registrar prefijos de clases con múltiples paths. Esto penaliza en rendimiento pues por cada solicitud de carga de plugins se debe examinar cada prefijo con cada path, para encontrar la clase. Aún así el componente <i>Zend_Loader_PluginLoader</i> puede crear una cache de plugins, es decir crea en tiempo de ejecución un archivo PHP dónde va añadiendo includes de todos los plugins de los que ya ha resuelto el path. Así que yo aconsejaría encarecidamente usar esta característica para entornos de producción (no tiene sentido ponerlo en entorno de desarrollo a no ser que se quiera medir el rendimiento de la aplicación).</p>
<pre>
&lt;?php
  $classFileIncCache = APPLICATION_PATH . &#039;/../data/pluginLoaderCache.php&#039;;
  if (file_exists($classFileIncCache)) {
    include_once $classFileIncCache;
  }
  if ($config-&gt;enablePluginLoaderCache) {
    Zend_Loader_PluginLoader::setIncludeFileCache($classFileIncCache);
  }
</pre>
<h2>Aún sigo necesitando mejor rendimiento en carga de clases, qué puedo hacer?</h2>
<p style="text-align:justify;">Si aún así, después de estos tips necesitas mejorar la carga de clases aún existe algún improvment más que se puede usar. En la versión 2.0 de Zend Framework, han mejorado el componente relativo a la carga de clases para sacar las partes deprecadas y para mejorar sustancialmente el rendimiento. Lo bueno es que este componente ya es estable y puede ser usado.</p>
<p style="text-align:justify;">Uno de los puntos del nuevo desarrollo del componente de autoloading en Zend Framework ha sido el crear el autoloader más rápido posible, es decir aquél que no tenga que calcular <strong>nada</strong> para conocer la ubicación de una clase pero que aún así sepa dónde están ubicadas todas las clases que se van a usar. Esto se ha traducido en un <strong>mapa de clases</strong>.</p>
<p style="text-align:justify;">En este caso, lo que propone Zend es que antes de hacer un deploy a producción se generen estos mapas de clases (un archivo con un array de clases cómo claves y paths cómo valores) para que la nueva clase <i>ClassMapAutoloader</i> (al fin y al cabo es un &#8220;autoloader tonto&#8221;) pueda disponer de ellos y mejorar el rendimiento. Si esto lo combinamos con APC que ya de por sí sin hacer nada acelera las aplicaciones web en PHP, tendríamos que poder ver una mejora sustancial del rendimiento.</p>
<h3>Y cómo lo puedo usar en mi Zend Framework 1.x?</h3>
<p style="text-align:justify;">Pues bien los chicos de Zend Framework se han encargado de hacer un mini port para Zend Framework 1.x y se puede localizar en el github personal de <a href="https://github.com/weierophinney/zf-examples/tree/feature/zf1-classmap/zf1-classmap" rel="nofollow" target="_blank">Matthew Weier O&#8217;phinney</a>, Techlead de Zend Framework, dónde se explica detenidamente cómo usarlo.</p>
]]></content:encoded>
			<wfw:commentRss>http://christian.soronellas.es/2011/10/09/autoloading-en-zend-framework/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Y ya estoy Certificado en PHP 5.3!</title>
		<link>http://christian.soronellas.es/2011/07/30/ya-estoy-certificado-en-php-53/</link>
		<comments>http://christian.soronellas.es/2011/07/30/ya-estoy-certificado-en-php-53/#comments</comments>
		<pubDate>Sat, 30 Jul 2011 14:28:31 +0000</pubDate>
		<dc:creator>Christian Soronellas</dc:creator>
				<category><![CDATA[Certificación PHP]]></category>
		<category><![CDATA[Desarrollo web]]></category>
		<category><![CDATA[certifiación php]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[php5.3]]></category>
		<category><![CDATA[zend]]></category>

		<guid isPermaLink="false">http://christian.soronellas.es/?p=363</guid>
		<description><![CDATA[A día de ayer, cosa de las 09.30h de la mañana, realicé el examen de certificación de PHP 5.3. Mis impresiones, a decir verdad, fueron que me esperava el examen un poco más difícil de lo qué realmente fue. Aunque sí qué es verdad qué había preguntas oscuras qué entrañaban cierta dificultad, creo que muchas [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align:justify;">A día de ayer, cosa de las 09.30h de la mañana, realicé el examen de certificación de PHP 5.3. Mis impresiones, a decir verdad, fueron que me esperava el examen un poco más difícil de lo qué realmente fue. Aunque sí qué es verdad qué había preguntas oscuras qué entrañaban cierta dificultad, creo que muchas de las preguntas podían sacarse usando la táctica de eliminación.</p>
<h3>Pocas preguntas específicas de PHP 5.3</h3>
<p style="text-align:justify;">Una de las cosas que más me llamó la atención fue que preguntas específicas a PHP 5.3 no hubo más que tres: Una de <strong>namespaces</strong> y de <strong>late static bindings</strong> bastante sencillas y una de <strong>closures</strong> un poco más rebuscada. Pero realmente, eché en falta más preguntas relativas en PHP 5.3</p>
<h3>Otros temas que se tocaron en el examen</h3>
<p style="text-align:justify;">Son los que ya se mencionan en las guías de Zend. Específicamente, de <strong>Databases</strong> me cayeron un par y las dos sobre transacciones bastante sencillas todo hay que decirlo. De fechas solo me cayó una, también sencillita. De <strong>XML</strong>, nada más que un par o tres de preguntas. Sobre todo hicieron foco en los <strong>PHP Basics</strong>, en el tema de <strong>Arrays</strong>, <strong>Web Features</strong>, algunas de <strong>Streams</strong> y de <strong>Security</strong>.</p>
<h3>Mi recomendación</h3>
<p style="text-align:justify;">Para todos aquellos qué estén leyendo esta entrada y quieran sacarse la <strong>certificación de PHP 5.3</strong>, sobretodo hacer foco en los puntos en los qué he hecho referencia en el párrafo anterior, obviamente sin olvidar los otros. Por otra parte, no creo qué sea indispensable pero si muy útil, y es que una semana antes de hacer el exámen tuve acceso a unos videos sobre formación en <strong>certificación PHP 5.3</strong> que proporciona Zend. Si podéis acceder a ellos de alguna manera los recomiendo por qué tratan preguntas parecidas a las del examen y sirven para ver en lo que se está fallando.</p>
<div class="zend-certified-logos" style="text-align:center">
    <img alt="Certificacion PHP 5.3" src="http://christian.soronellas.es/wp-content/uploads/2011/07/zce-php5-3-logo.gif" />
</div>
]]></content:encoded>
			<wfw:commentRss>http://christian.soronellas.es/2011/07/30/ya-estoy-certificado-en-php-53/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>PHP 5.4 – El espectáculo continúa</title>
		<link>http://christian.soronellas.es/2011/07/02/php-5-4-%e2%80%93-el-espectaculo-continua/</link>
		<comments>http://christian.soronellas.es/2011/07/02/php-5-4-%e2%80%93-el-espectaculo-continua/#comments</comments>
		<pubDate>Sat, 02 Jul 2011 14:07:32 +0000</pubDate>
		<dc:creator>Christian Soronellas</dc:creator>
				<category><![CDATA[Desarrollo web]]></category>
		<category><![CDATA[php php5.4]]></category>

		<guid isPermaLink="false">http://christian.soronellas.es/?p=356</guid>
		<description><![CDATA[Muchos todavía estamos descubriendo las bondades de PHP5.3 y sus novedades y aún hay muchos sitios importantes que corren sobre PHP5.2. Sin embargo, el equipo que hace PHP no descansa y recientemente han publicado la primera versión alpha de lo que será PHP5.4 que promete muchas mejoras tanto en rendimiento como en funcionalidades.]]></description>
			<content:encoded><![CDATA[<p style="text-align:justify">Muchos todavía estamos descubriendo las bondades de PHP5.3 y sus novedades y aún hay muchos sitios importantes que corren sobre PHP5.2. Sin embargo, el equipo que hace PHP no descansa y recientemente han publicado la primera versión alpha de lo que será PHP5.4 que promete muchas mejoras tanto en rendimiento como en funcionalidades.</p>
<p style="text-align:justify;">Mi compañero <strong><a rel="friend met co-worker colleague" href="http://www.ricardclau.com/2011/07/php-5-4-el-espectaculo-continua/">Ricard Clau</a></strong> y yo hemos estado haciendo algunas pruebas con esta versión y aquí os presentamos algunas de las novedades que consideramos más destacadas.</p>
<h2>Traits</h2>
<p style="text-align:justify;">Probablemente el plato estrella de la versión. Un trait viene a ser algo así como un trozo de clase que podemos importar en varios sitios. Además, en una clase hija, podemos heredar de varios traits. Y con esto, en parte, conseguimos la tan deseada por algunos herencia múltiple en cierta manera.</p>
<pre>
&lt;?php
trait Singleton
{
  private static $_instance;
  private function __construct(){}

  public function __clone()
  {
    throw new Exception(&#039;This object cannot be cloned!&#039;);
  }

  public static function getInstance()
  {
    if (null === static::$_instance) {
      static::$_instance = new static();
    }

    return static::$_instance;
  }
}

class Product
{
  use Singleton;
}

$product = Product::getInstance();
</pre>
<p style="text-align:justify;">Más fácil aún hacer Singletons y sobretodo, centralizado el código de instanciación.</p>
<p style="text-align:justify;">Podéis ver algunos ejemplos más con, por ejemplo, tratamiento de colisiones al hacer el use de varios traits con funciones idénticas y algunos otros ejemplos en <a href="http://simas.posterous.com/new-to-php-54-traits">esta web</a>.</p>
<h2>Array Deferencing</h2>
<p style="text-align:justify;">Esto es algo bastante molón que hasta ahora no se podía hacer. Cuántas veces habéis tenido que llamar a una función que devuelve un array y al tener que tratar su resultado habéis pensado: Qué bien me iría poder poner corchetes al resultado de la función directamente. Pues eso por fin se puede hacer:</p>
<pre>
&lt;?php
echo call_user_func(function(){return array(&#039;test&#039;, &#039;deferencing&#039;);})[1];
</pre>
<p style="text-align:justify;">Aquí veríamos un ‘deferencing’ en consola. Muy a lo JavaScript.</p>
<h2>DTrace</h2>
<p style="text-align:justify;">El DTrace es un sistema de debug de aplicaciones en tiempo real en entornos de producción. Usa scripts en &#8220;D&#8221; para debuggar partes de la aplicación al alcanzar ciertas condiciones (qué X archivo se ha abierto, qué Y linea se ha alcanzado, etc. ) y así aportar visibilidad en entornos de producción. Lejos ha quedado aquel tiempo en que las webs eran solamente una sección de noticias y un triste catálogo. Y a veces, tenemos aplicaciones monstruosas donde es complicado ver la secuencia de llamadas. Seguro que esto ayuda a encontrar errores en nuestra aplicación.</p>
<h2>Mejoras en memoria y rendimiento de Zend Engine</h2>
<p style="text-align:justify;">Este punto es súper importante que no se descuide nunca. Bien es cierto que con los cacheos (HTTP_Cache, CDNs varios, Memcached, etc.) con APC para Opcode Cache y el resto de técnicas de high-performance se optimiza mucho. Pero al final, optimizando el core de PHP se ganará muchísimo ya que por la naturaleza de PHP, cada Request vuelve a empezar todo y el proceso de bootstraping debe ir lo más rápido posible.</p>
<h2>Paso a PECL de la extensión de SQLite</h2>
<p style="text-align:justify;">Cada vez se usa más SQLite, para testear la BBDD, para entornos de desarrollo locales y es importante tener claro cómo trabajar con ella y cómo instalar la extensión para PHP.</p>
<h2>Rotura con algunas miserias del pasado</h2>
<p style="text-align:justify;">Desaparecen por fin settings de tan infausto recuerdo como safe_mode, register_globals (cuánto daño ha hecho), register_long_arrays, allow_call_time_pass_reference, etc.</p>
<p style="text-align:justify;">También desaparecen las siguientes funciones relacionadas con el tratamiento de sesiones: session_is_registered(), session_register() and session_unregister()</p>
<p style="text-align:justify;">Además, el tema del break y el continue, queda de la siguiente manera: podemos hacer break y continue para salir de un bucle, break 2 o continue 3 para saltarnos varias iteraciones pero no podemos hacer un break $i. Nos dará un error de algo así como Expected Constant Value.</p>
<pre>
&lt;?php
  public function testBreakI()
  {
    $z = 2;
    for($i = 0; $i &lt; 10; $i++)
      for($j = 0; $j &lt; 10; $j++)
        if ($i == 2 &amp;&amp; $j == 2)
          break $z;

    var_dump($i, $j);
  }
  testBreakI();
</pre>
<p style="text-align:justify;">Y en php.ini, el default encoding es UTF-8, el short tag de template <?= estará habilitado siempre y algunas cositas más que podéis ver en PHP.net</p>
<h2>Conclusión</h2>
<p style="text-align:justify;">Es para mí, notícia de gran alegría, ver cómo un lenguaje al qué le profeso auténtica devoción va evolucionando día a día. Desde aquí dar las gracias a toda la comunidad de PHP por hacerlo más grande versión a versión. Y qué siga así por mucho más.</p>
<p style="text-align:justify;">Si bien es cierto qué siempre hay cosas qué mejorar, pues soy firme creyente en qué siempre hay margen de mejora, cómo por ejemplo el tema de la superpoblación de frameworks o la perversión de CMSs.</p>
<p style="text-algin:justify;">Pero &#8230; que grande qué es PHP!</p>
]]></content:encoded>
			<wfw:commentRss>http://christian.soronellas.es/2011/07/02/php-5-4-%e2%80%93-el-espectaculo-continua/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Acerca de los ciclos de desarrollo, respetuosamente.</title>
		<link>http://christian.soronellas.es/2011/06/20/acerca-de-los-ciclos-de-desarrollo-respetuosamente/</link>
		<comments>http://christian.soronellas.es/2011/06/20/acerca-de-los-ciclos-de-desarrollo-respetuosamente/#comments</comments>
		<pubDate>Mon, 20 Jun 2011 21:34:26 +0000</pubDate>
		<dc:creator>Christian Soronellas</dc:creator>
				<category><![CDATA[Desarrollo web]]></category>
		<category><![CDATA[ciclo de desarrollo]]></category>
		<category><![CDATA[desarrollo]]></category>

		<guid isPermaLink="false">http://christian.soronellas.es/?p=346</guid>
		<description><![CDATA[Recientemente me he visto envuelto en una discusión de alto nivel en LinkedIn, pues un compañero y amigo de allí dónde trabajo me recomendó qué le echara un vistazo por ciertos comentarios vertidos en ese hilo. El título del hilo, JQuery or YUI? Pro&#8217;s and Cons. Dentro del grupo Front end Developer Group. Un interesantísimo [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">Recientemente me he visto envuelto en una discusión de alto nivel en LinkedIn, pues un compañero y amigo de allí dónde trabajo me recomendó qué le echara un vistazo por ciertos comentarios vertidos en ese hilo. El título del hilo, <strong>JQuery or YUI? Pro&#8217;s and Cons</strong>. Dentro del grupo <em>Front end Developer Group</em>. Un interesantísimo debate. Lo recomiendo a quién me esté leyendo, tenga facilidad con el inglés y sobretodo le interesen temas de front-end.</p>
<h2>Está mi ciclo de desarrollo en &#8230; peligro?</h2>
<p style="text-align: justify;">A lo largo de este debate cierto individuo, tengo qué decir con toda sinceridad que equivocadamente, pone por delante de cualquier otra decisión técnica el valor qué tiene la velocidad de ejecución cuándo se trata de decidir usar un framework de JS. Si ya te has puesto las manos a la cabeza, por favor, espera a acabar de leerme.</p>
<p style="text-align: justify;">Es evidente qué la velocidad es un factor a tener en cuenta cuándo hemos de decidir usar una librería u otra. Pero nunca puede ser el único motivo por el cuál decantarse. Estaríamos incurriendo en una mala decisión, qué nos puede llegar a afectar muy negativamente en un futuro, ya qué las decisiones técnicas deben venir siempre motivadas por unas necesidades de negocio. Estás necesidades responden a la medición de unos costes sobre las mismas oportunidades de negocio qué nunca se pueden menospreciar. Es decir, me explico. Cuál puede ser el coste, para un negocio, de perder una oportunidad? Un gran oportunidad? Puede suponer perder el hecho posicionarse delante de la competencia en una posición realmente privilegiada. Luego la propia marca empieza a perder valor (o le cuesta horrores recuperarlo), delante de la competencia. Y esto, sólo sería el principio de la cadena de consecuencias. Y eso lo puede solucionar un factor cómo la velocidad de ejecución de una librería JS? Esto qué parece tan mezquinamente lógico, para ciertos individuos no lo es. Se debe ir con calma y humildad.</p>
<h2>Qué impacto puede tener esto en el ciclo de desarrollo?</h2>
<p style="text-align:justify;">El caso más simple y más fácil de ver, es el del típico tío de negocios, cliente, Product Owner qué quiere ver lo qué ha solicitado a desarrollo, online lo antes posible. Obviamente, su misión será presionar para conseguirlo cuánto antes. Hasta aquí, nada raro. Nada qué no se viva en una empresa cotidianamente. Pero qué pasa cuándo por ejemplo, el diseño de esa librería tan rápida no permite desarrollar la nueva funcionalidad tan rápidamente? O cuándo la curva de aprendizaje es realmente pronunciada? O cuándo resulta qué cómo consecuencia del pésimo diseño de ese framework, tenemos algo muy costoso de mantener? Pues qué ese ciclo de desarrollo se puede ver incrementado sensiblemente, debido al coste de implementar/mantener la nueva funcionalidad. O de aprender cómo funciona la librería. O un largo etcétera.</p>
<p style="text-align:justify;">Y ¡Carámba! Ahora a <i>negocio</i>, ya no le sirve de nada qué usemos algo realmente <strong>ultrarápido</strong>, pues todo lo qué ganamos con un aspecto, lo perdemos irremediablemente al perder esa oportunidad de negocio. Después, de su pertinente tirón de orejas. E incluso, dependiendo de la oportunidad perdida, nuestro puesto de trabajo.</p>
<h2>Conclusiones finales</h2>
<p style="text-align:justify;">Elegir una herramienta de trabajo, <strong>no es un juego</strong>. Es algo de suma importancia y no debe nunca ser tomado cómo tal. De ello puede depender toda una empresa, por lo qué se deben considerar todos los requerimientos impuestos por negocio. Sin excepción.</p>
]]></content:encoded>
			<wfw:commentRss>http://christian.soronellas.es/2011/06/20/acerca-de-los-ciclos-de-desarrollo-respetuosamente/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Patrón Service Layer en Zend Framework</title>
		<link>http://christian.soronellas.es/2011/02/08/patron-service-layer-en-zend-framework/</link>
		<comments>http://christian.soronellas.es/2011/02/08/patron-service-layer-en-zend-framework/#comments</comments>
		<pubDate>Tue, 08 Feb 2011 19:11:05 +0000</pubDate>
		<dc:creator>Christian Soronellas</dc:creator>
				<category><![CDATA[Desarrollo web]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[json-rpc]]></category>
		<category><![CDATA[service]]></category>
		<category><![CDATA[service layer]]></category>
		<category><![CDATA[zend framework]]></category>
		<category><![CDATA[zend json]]></category>
		<category><![CDATA[zend json server]]></category>

		<guid isPermaLink="false">http://christian.soronellas.es/?p=314</guid>
		<description><![CDATA[Introducción Muchas veces las aplicaciones web se encuentran con la necesidad de implementar ciertas funcionalidades o características qué deben responder al navegador en diferentes formas. Un ejemplo de ello son las aplicaciones web funcionando con AJAX y solicitando datos al servidor de forma asíncrona sin bloquear la UI del navegador, para así poder ofrecer al [...]]]></description>
			<content:encoded><![CDATA[<h2>Introducción</h2>
<p style="text-align:justify;">Muchas veces las aplicaciones web se encuentran con la necesidad de implementar ciertas funcionalidades o características qué deben responder al navegador en diferentes formas. Un ejemplo de ello son las aplicaciones web funcionando con <strong>AJAX</strong> y solicitando datos al servidor de forma asíncrona sin bloquear la UI del navegador, para así poder ofrecer al usuario una mejor y más rica experiencia de usuario. Es por ello también, qué se produjo el nacimiento de las <em>restful web applications</em> (de las qué voy a hablar en venideras entradas :). Pero el objeto de esta entrada se centra en ofrecer una via de respuesta con formato <em>JSON</em> implementando el protocolo <strong>JSON-RPC 2.0</strong> a través del componente, <strong>Zend_Json_Server</strong> de Zend Framework. Un método un poco más simple qué REST pero algo menos complicado que, bajo mi humilde punto de vista, puede servir de enfoque para proyectos web no demasiado grandes.</p>
<h2>Patrón Service Layer</h2>
<p style="text-align:justify">Tal cómo <a style="font-weight:bolder;" href="http://martinfowler.com/eaaCatalog/serviceLayer.html" target="_blank">define</a> Randy Stafford en el libro de Martin Fowler el patrón <strong>Service Layer</strong> <em>define un límite de la aplicación con una capa de servicios que establece un conjunto de operaciones disponibles y coordina la respuesta de la aplicación en cada operación</em>. En otras palabras, estaríamos hablando de una capa qué actuaría por encima del modelo de dominio y que proporcionaría los datos qué se le pidieran a través de los métodos qué definiera. Así, por ejemplo, podríamos tener un <em>service</em> de pedidos (para sólo obtener datos de pedidos), o un <em>service</em> de productos, o de usuarios, etc.</p>
<p style="text-align:justify">En este caso no voy a entrar en detalles acerca de cómo implementar otros formatos de respuesta, pues es bien sencillo a partir de revisar el ejemplo qué todo seguido voy a exponer.</p>
<h2>Sí, sí, muy guapo &#8230; pero y ahora qué?</h2>
<p style="text-align:justify">Pues todo seguido voy a poner un ejemplo de una manera cómo se podría implementar sin llegar a ser demasiado complicado. Cómo siempre va a estar basado en una instalación limpia de <strong>Zend Framework</strong>. Así qué lo primero es iniciar nuevo proyecto y lo podemos hacer mediante</p>
<pre>
> zf create project .
> zf enable layout
> zf configure db-adapter 'adapter=PDO_SQLITE&#038;dbname=APPLICATION_PATH "/../data/db/database-development.db"' development
> zf create db-table section Section
> zf create model Section
> touch data/db/database-development.db
> sqlite3 data/db/database-development.db
</pre>
<p style="text-align:justify">Luego procederemos a crear la base de datos con la qué vamos a trabajar en el entorno de desarrollo.</p>
<pre>
CREATE TABLE section (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
title VARCHAR(50) NOT NULL,
BODY TEXT NOT NULL
);
</pre>
<p style="text-align:justify">Una vez creado el nuevo proyecto y la base de datos, procedemos a crear toda la capa qué interactuará con el <em>Domain Model</em>.</p>
<pre>
/**
 * File located at library/Application/Services/Sections.php
 */
class Application_Services_Sections
{
    /**
     * The sections table instance
     * @var Application_Model_DbTable_Section
     */
    protected $_sectionsTable;

    /**
     * A setter to inject the sections table
     */
    public function setTablesSection(Zend_Db_Table_Abstract $sectionsTable)
    {
      $this->_sectionsTable = $sectionsTable;
    }

    /**
     * Returns a list of avaliable sections
     * @return array
     */
    public function getSections()
    {
      if (null === $this->_sectionsTable) {
        $this->_sectionsTable = new Application_Model_DbTable_Sections();
      }

      return $this->_sectionsTable->fetchAll()->toArray();
    }

    /**
     * Returns a single section by its ID
     * @param integer $id The section ID
     * @return array
     */
    public function getSection($id)
    {
      if (null === $this->_sectionsTable) {
        $this->_sectionsTable = new Application_Model_DbTable_Sections();
      }

      return $this->_sectionsTable->find($id)->current()->toArray();
    }
}
</pre>
<p style="text-align:justify">De este modo queda definido nuestro punto de entrada a la aplicación por <strong>JSON-RPC</strong>, bajo el qué hay disponibles dos operaciones: <em>getSections</em>, qué devuelve una lista de secciones y <em>getSection</em>, qué dado un ID de sección devuelve su correspondiente registro. Ahora procederemos a crear el controlador encargado de proporcionar la respuesta de las llamadas por medio de <strong>JSON-RPC</strong> y sus correspondientes rutas para que la aplicación pueda responder por los diferentes servicios qué se le soliciten. Veamos.</p>
<pre>
/**
 * File located at application/controllers/ServiceController
 */
class ServiceController extends Zend_Controller_Action
{
    /**
     * The JSON-RPC server instance
     * @var Zend_Json_Server
     */
    protected $_jsonServer = null;

    /**
     * The inflector used to map all the services to the classes correctly
     * @var Zend_Filter_Inflector
     */
    protected $_inflector = null;

    /**
     * (non-PHPdoc)
     * @see library/Zend/Controller/Zend_Controller_Action::init()
     */
    public function init()
    {
        /**
         * Initializes the controller, and disable the viewRenderer and the layout
         * only for this controller. Initializes the inflector and then starts the
         * Zend_Json_Server.
         */
    	$this->_helper->getHelper('viewRenderer')->setNoRender(true);
    	$this->_helper->getHelper('layout')->disableLayout();

    	$this->_inflector = new Zend_Filter_Inflector(':classname');
    	$this->_inflector->setFilterRule(
    	   'classname', array('Word_UnderscoreToDash', 'Word_DashToCamelCase')
    	);

        $this->_jsonServer = new Zend_Json_Server();
    }

    /**
     * Prepares the JSON-RPC server with the service (class :) requested. The reques
     * ted service should exist on the "library/Application/Service/ServiceName.php",
     * being "ServiceName" the service name.
     * For example, to call an operation form the service "order-detail", the file
     * "library/Application/Service/OrderDetail.php" must exist.
     * @param string $service The requested service
     */
    protected function _prepareJsonRpcServer($service)
    {
    	$this->_jsonServer->setClass(
            'Application_Service_' . $this->_inflector->filter(
                array('classname' => $service)
            )
    	);
    }

    /**
     * Handle a JSON-RPC Request
     */
    public function indexAction()
    {
    	$this->_prepareJsonRpcServer($this->getRequest()->getParam('service'));
        $this->_jsonServer->handle();
    }

    /**
     * Return the Service descriptor
     */
    public function smdAction()
    {
    	$service = $this->getRequest()->getParam('service');
    	$this->_prepareJsonRpcServer($service);
        $this->_jsonServer->setTarget('/services/' . strtolower($service))
                                     ->setEnvelope(Zend_Json_Server_Smd::ENV_JSONRPC_2);

        $this->getResponse()->setHeader('Content-type', 'application/json');
        $this->getResponse()->setBody($this->_jsonServer->getServiceMap());
    }
}
</pre>
<p style="text-align:justify">Este controlador, tiene 2 propiedades. Una para albergar una instancia del servidor de <strong>JSON-RPC</strong> y otra para albergar una instancia del mapper que actuará de puente entre los servicios disponibles y sus classes correspondientes. Además definimos dos posibles acciones: la acción por defecto, desde la qué se van a realizar todas las operaciones (<em>indexAction</em>) y otra acción (<em>smdAction</em>) para enviar un descriptor del servicio a quién lo solicite. Para la ejecución de todas las acciones, vamos a decirle a este controlador qué no haga render de la vista y que no la vista con su layout correspondiente. Con el controlador definido, ahora sólo queda definir las rutas correspondientes.</p>
<pre>
; File located at application/configs/routes.ini
; Application routes
; The main services endpoint
routes.service.route = "services/:service"
routes.service.defaults.controller = service
routes.service.defaults.action = index
; The service descriptor route
routes.smd.route = "services/service-descriptor/:service"
routes.smd.defaults.controller = service
routes.smd.defaults.action = smd
</pre>
<p>Añadimos una entrada en el archivo de bootstrap para qué se haga uso de las rutas en la aplicación</p>
<pre>
/**
 * File located at application/Bootstrap.php
 */
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
    public function _initApplicationRoutes()
    {
    	$this->bootstrap('frontcontroller');
    	$this->getResource('frontcontroller')
    	       ->getRouter()
    	       ->addConfig(
                  new Zend_Config_Ini(
                      APPLICATION_PATH . DIRECTORY_SEPARATOR . 'configs' . DIRECTORY_SEPARATOR . 'routes.ini'
                  ),
                  'routes'
              );
    }
}
</pre>
<p style="text-align:justify">Ya con casi todo el tinglado montado, sólo nos queda montar la parte del cliente qué va a contactar y consumir los servicios disponibles. Para ello, yo he implementado un cliente muy muy sencillo a modo de ejemplo a través del plugin de <em>jQuery</em>, <a href="https://github.com/datagraph/jquery-jsonrpc" target="_blank"><strong>jQuery JSON RPC 2.0</strong></a>. Así qué bajamos una copia del proyecto y copiamos el archivo <em>jquery.jsonrpc.js</em> a la carpeta js (sino existe la creamos) de nuestro directorio <em>public</em>. Además allí también crearemos el archivo <em>site.js</em> con el siguiente código.</p>
<pre>
$(document).ready(function() {
	$(&#039;a&#039;).click(function(event) {
		$.jsonRPC.setup({
			endPoint: &#039;/services/sections&#039;
		});

		$.jsonRPC.request(&#039;getSections&#039;, {}, {
			success: function(result) {
				var html = &#039;&lt;ul id=&quot;sections&quot; class=&quot;list&quot;&gt;&#039;;
				$.each(result[&#039;result&#039;], function(index, section) {
					html += &#039;&lt;li class=&quot;section&quot;&gt;&#039; + section.title + &#039;&lt;/li&gt;&#039;;
				});
				html += &#039;&lt;/ul&gt;&#039;;

				$(document.body).append(html);
			}
		});

		event.preventDefault();
	});
});
</pre>
<p style="text-align:justify">Y ya para finalizar, sólo hace falta añadir una interacción en la presentación del controlador <em>IndexController</em> para poder demostrar todo este comportamiento. Además también añadiremos las llamadas necesarias a los correspondientes archivos de javascript para qué sea efectiva la demostración.</p>
<pre>
&lt;!-- File located at application/layouts/scripts/layout.phtml --&gt;
&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML Basic 1.1//EN&quot;
    &quot;http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd&quot;&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;title&gt;JSON RPC Test&lt;/title&gt;
    &lt;/head&gt;

    &lt;body&gt;
        &lt;?php echo $this -&gt; layout() -&gt; content; ?&gt;
        &lt;script type=&quot;text/javascript&quot; src=&quot;https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js&quot;&gt;&lt;/script&gt;
        &lt;script type=&quot;text/javascript&quot; src=&quot;/js/jquery.jsonrpc.js&quot;&gt;&lt;/script&gt;
        &lt;script type=&quot;text/javascript&quot; src=&quot;/js/site.js&quot;&gt;&lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;
</pre>
<pre>
&lt;!-- File located at application/views/scripts/index/index.phtml --&gt;
&lt;p&gt;&lt;a href=&quot;#&quot;&gt;Get a list of sections&lt;/a&gt;&lt;/p&gt;
</pre>
<h2>Concluyendo</h2>
<p style="text-align:justify;">Con todo lo dicho hasta ahora deberíamos ser capaces de poder invocar métodos remotos mediante <strong>JSON-RPC</strong>. Y esto puede ser extrapolado a lo que se quiera hacer. Es decir, si tenemos un e-commerce del qué queremos conocer el detalle de un pedido asíncronamente, esta puede ser una manera (no la única) de hacerlo ordenadamente, qué a mi particularmente me gusta. Y no soy el único puesto qué sitios más grandes con altos volumen de tráfico (Facebook, Tuenti, etc.) ya lo estan llevando a la práctica (esto y algunas cosas más).</p>
<p style="text-align:justify;">Cómo siempre, voy a dejar una copia del código colgada en mi cuenta de <a href="https://github.com/theUniC/zf-service-layer" target="_blank">github</a> para quién le interese poder trastear un poco con todo esto.</p>
]]></content:encoded>
			<wfw:commentRss>http://christian.soronellas.es/2011/02/08/patron-service-layer-en-zend-framework/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Zend Framework, Zend View and Twig</title>
		<link>http://christian.soronellas.es/2011/01/14/zend-framework-zend-view-and-twig/</link>
		<comments>http://christian.soronellas.es/2011/01/14/zend-framework-zend-view-and-twig/#comments</comments>
		<pubDate>Fri, 14 Jan 2011 13:42:42 +0000</pubDate>
		<dc:creator>Christian Soronellas</dc:creator>
				<category><![CDATA[Web development]]></category>
		<category><![CDATA[smarty]]></category>
		<category><![CDATA[smarty 2]]></category>
		<category><![CDATA[smarty 3]]></category>
		<category><![CDATA[twig]]></category>
		<category><![CDATA[zend framework]]></category>
		<category><![CDATA[zend view]]></category>
		<category><![CDATA[zend_view]]></category>

		<guid isPermaLink="false">http://christian.soronellas.es/?p=292</guid>
		<description><![CDATA[Introduction to PHP template engines In order to contextualize this post I have to talk a bit about PHP template engines. Template engines are libraries intended to abstract all of an application views looking for the maximum eficiency and the best code reuse. If we have product listings, for example, on different categorizations, It allow [...]]]></description>
			<content:encoded><![CDATA[<h2>Introduction to PHP template engines</h2>
<p style="text-align:justify;">In order to contextualize this post I have to talk a bit about PHP template engines. Template engines are libraries intended to abstract all of an application views looking for the maximum eficiency and the best code reuse. If we have product listings, for example, on different categorizations, It allow us to define a common UI for the categories. This gives more flexibility to the application, and gives sense to the <strong>V</strong> of <strong>MVC</strong>. All thanks to the <a href="http://es2.php.net/manual/es/book.outcontrol.php" target="_blank">output</a> control that PHP provides of (which was impossible with the old ASP, for example).</p>
<p style="text-align:justify;">There are a lot of template engines in PHP. If we <strong><a href="http://www.google.com/search?sourceid=chrome&#038;ie=UTF-8&#038;q=php+template+engine" target="_blank">search</a></strong> on google, we will see it. But the <i>de-facto standard</i> till now was <strong><a href="http://smarty.net" target="_blank">Smarty</a></strong>. Yes. I said  <strong><em>was</em></strong>. Because until now, several template engines have been released which, on my point of view, have questioned Smarty as the PHP template engine by excellence. One of them, and I&#8217;m going to point the object of this entry, is <a href="http://www.twig-project.org" target="_blank"><strong>Twig</strong></a>.</p>
<h2>Smarty 3 vs Twig</h2>
<h3>Why not to use Smarty 3</h3>
<p style="text-align:justify"><strong>All told</strong>. Smarty is a great library to separate the view and the application logic. It accomplishes its objective and accomplishes it, more than satisfies. However, It&#8217;s second version became outdated with PHP 5 and his new object handling model. Because of this, <a href="http://www.smarty.net/v3_overview" target="_blank">Smarty 3</a> was released. Among the new features of Smarty 3, with those of the previous version, we can emphasize:</p>
<ul style="margin-left:25px;">
<li>Rewritten for PHP 5</li>
<li>A real syntax lexer (its previous version didn&#8217;t have one)</li>
<li>Template inheritance</li>
<li>Variable autoescaping</li>
<li>Function definition on template level</li>
</ul>
<p style="text-align:justify;">And there are more features. Maybe the question now could be, and what&#8217;s wrong? Seems that all said until now looks good. But what about the <strong>performance</strong>? How is going to affect to our application performance the inclusion of one or another engine? To answer this question I recommend the reading of a Fabien Potencier post, <a href="http://fabien.potencier.org/article/34/templating-engines-in-php" target="_blank"><strong>where stablishes a comparative between PHP template engines</strong></a>, and each draw its own conclusions. At the end, each one knows the project that he/she is developing and each one knows what is appropiate. <strong>I&#8217;ll stick with Twig.</strong></p>
<h3>Why yes to use Twig</h3>
<p style="text-align:justify;">First of all, and as I said before, because performance reasons. As told in Fabien Potencier&#8217;s post there are performance differences between the two engines. But beyond that, the decision to use this component can imply another aspects of itself. Because of this, all that follows this comes basically from my point of view.</p>
<p style="text-align:justify;">Secondly, this engine comes with features already developed that doesn&#8217;t come shipped with Smarty, besides all the features of Smarty that already Twig integrates. One of them, and I have to say that I like a lot, is its <strong>Sandbox</strong> mode. The Sandbox mode, allows to restrict <strong>which features the template editor will be allowed to use.</strong>. I refer to for example: If I don&#8217;t want the <em>web designer</em> to use the <em>if</em> structure, by the Twig <em><strong>Sandbox</strong></em> mode, he/she won&#8217;t be allowed to use it. An this is for any feature of the engine. Even Twig allows to restrict features of our model classes. <strong>Almost impressive</strong>.</p>
<p style="text-align:justify;">Thirdly and for the last, <strong>I prefer the Twig extensibility model more over than the Smarty one</strong>. I believe it&#8217;s easier to add functionality to Twig. Smarty, on its third version, <strong>still comes with the Smarty 2 plugin model</strong> and sincerely, with PHP 5.3 rising, I miss a more object oriented extensibility model.</p>
<h2>Zend_View and its agnosticism</h2>
<p style="text-align:justify;">I say <strong>agnosticism</strong> because it&#8217;s one of the component strongest feature. <strong>Zend_View</strong> it&#8217;s <em>template engine</em> agnostic, mostly for the <em>Zend_View_Interface</em> component, becoming PHP itself the <em>template engine</em> by default. And that will be, on this post, the way I&#8217;m going implement Twig as a Zend_View extension and override the default instance of Zend_View on runtime, by our (already known :) abstract class Zend_Application_Resource_ResourceAbstract implementation.</p>
<pre>
&lt;?php

// File located at &quot;library/Twig/Zend/View/Twig/TwigImplementation.php
require_once &#039;Zend/View/Interface.php&#039;;
require_once &#039;Twig/Autoloader.php&#039;;

class Twig_Zend_View_Twig_TwigImplementation
    implements Zend_View_Interface
{
	/**
	 * The twig loader instance
	 * @var Twig_Environment
	 */
	protected $_twigEnv;

	/**
	 * The twig loader instance
	 * @var Twig_Loader_Interface
	 */
	protected $_twigLoader;

	/**
	 * A map of all registered variables
	 * @var array
	 */
	protected $_variablesMap = array();

	/**
	 * Class constructor
	 * @param string $templateBasePath The views base path
	 * @param array $envOptions
	 */
	public function __construct($templateBasePath, array $envOptions = array())
	{
		$zendAutoloader = Zend_Loader_Autoloader::getInstance();
		$zendAutoloader -&gt; pushAutoloader(array(&#039;Twig_Autoloader&#039;, &#039;autoload&#039;));

		$this -&gt; _twigLoader = new Twig_Loader_Filesystem($templateBasePath);
		$this -&gt; _twigEnv = new Twig_Environment($this -&gt; _twigLoader, $envOptions);
	}

	/**
	 * (non-PHPdoc)
	 * @see library/Zend/View/Zend_View_Interface::getEngine()
	 * @return Twig_Environment
	 */
	public function getEngine()
	{
		return $this -&gt; _twigEnv;
	}

	/**
	 * (non-PHPdoc)
	 * @see library/Zend/View/Zend_View_Interface::setScriptPath()
	 */
	public function setScriptPath($path)
	{
	 	$this -&gt; _twigEnv -&gt; getLoader() -&gt; setPaths($path);
	}

	/**
	 * (non-PHPdoc)
	 * @see library/Zend/View/Zend_View_Interface::getScriptPaths()
	 */
	public function getScriptPaths()
	{
		return $this -&gt; _twigEnv -&gt; getLoader() -&gt; getPaths();
	}

	/**
	 * (non-PHPdoc)
	 * @see library/Zend/View/Zend_View_Interface::setBasePath()
	 */
	public function setBasePath($path, $classPrefix = &#039;Zend_View&#039;)
	{
		$this -&gt; setScriptPath($path);
	}

	/**
	 * (non-PHPdoc)
	 * @see library/Zend/View/Zend_View_Interface::addBasePath()
	 */
	public function addBasePath($path, $classPrefix = &#039;Zend_View&#039;)
	{
		$this -&gt; setScriptPath($path);
	}

	/**
	 * (non-PHPdoc)
	 * @see library/Zend/View/Zend_View_Interface::__set()
	 */
	public function __set($key, $val)
	{
		$this -&gt; _variablesMap[$key] = $value;
	}

	/**
	 * (non-PHPdoc)
	 * @see library/Zend/View/Zend_View_Interface::__isset()
	 */
	public function __isset($key)
	{
		return isset($this -&gt; _variablesMap[$key]);
	}

	/**
	 * (non-PHPdoc)
	 * @see library/Zend/View/Zend_View_Interface::__unset()
	 */
	public function __unset($key)
	{
		unset($this -&gt; _variablesMap[$key]);
	}

	/**
	 * (non-PHPdoc)
	 * @see library/Zend/View/Zend_View_Interface::assign()
	 */
	public function assign($key, $value = NULL)
	{
		if (!is_null($value)) {
			$this -&gt; _variablesMap[$key] = $value;
		} elseif (is_array($key)) {
			$this -&gt; _variablesMap = array_merge($this -&gt; _variablesMap, $key);
		}
	}

	/**
	 * (non-PHPdoc)
	 * @see library/Zend/View/Zend_View_Interface::clearVars()
	 */
	public function clearVars()
	{
		$this -&gt; _variablesMap = array();
	}

	/**
	 * (non-PHPdoc)
	 * @see library/Zend/View/Zend_View_Interface::render()
	 */
	public function render($name)
	{
		$template = $this -&gt; _twigEnv -&gt; loadTemplate($name);
		return $template -&gt; render($this -&gt; _variablesMap);
	}
}
</pre>
<p style="text-align:justify;">This class will serve us to inject Twig in the <strong>Zend Application</strong> context, as a Zend_View_Interface implementation. Now the next step will be override the Zend_View instance on runtime. And this can be done by creating a class that inherits of <strong>Zend_Application_Resource_ResourceAbstract</strong>.</p>
<pre>
&lt;?php

// File located at &quot;library/Twig/Zend/View/Twig/Twig.php&quot;
require_once &#039;Zend/Application/Resource/ResourceAbstract.php&#039;;
require_once &#039;Twig/Zend/View/Twig/TwigImplementation.php&#039;;

defined(&#039;DS&#039;)
    || define(&#039;DS&#039;, DIRECTORY_SEPARATOR);

class Twig_Zend_View_Twig_Twig
    extends Zend_Application_Resource_ResourceAbstract
{
	/**
	 * The Zend_View_TwigImplementation instance
	 * @var Zend_View_TwigImplementation
	 */
	protected $_view;

	/**
	 * (non-PHPdoc)
	 * @see library/Zend/Application/Resource/Zend_Application_Resource_Resource::init()
	 */
	public function init()
	{
		return $this -&gt; _getView();
	}

	/**
	 * Returns the Zend_View_TwigImplementationInstance. If not initialized,
	 * initializes the instance
	 */
	protected function _getView()
	{
		if (null === $this -&gt; _view)
		{
			$options = $this -&gt; getOptions();
			$view = new Twig_Zend_View_Twig_TwigImplementation(APPLICATION_PATH . DS . &#039;views&#039; . DS . &#039;scripts&#039;, $options);
			Zend_Controller_Action_HelperBroker::getStaticHelper(&#039;viewRenderer&#039;)
                -&gt; setView($view)
                -&gt; setViewSuffix(&#039;twig&#039;);

			$this -&gt; _view = $view;
		}

		return $this -&gt; _view;
	}
}
</pre>
<p style="text-align:justify;">By the call to the <em>setView</em> method of the <em>viewRenderer</em> helper, the Zend_View instance will be overriden by our implementation, previously instanciated. Also we notify to the helper, about our view suffix: <em>.twig</em>. Then just need to modify our <em>application.ini</em> to begin using the engine.</p>
<pre>
; ...
; Twig config
pluginPaths.Twig_Zend_View_Twig_ = "Twig/Zend/View/Twig/"
resources.twig.cache = APPLICATION_PATH "/../cache/twig"
</pre>
<p style="text-align:justify">Now rename our views, from index.phtml to index.twig</p>
<pre>
&lt;!-- views/scripts/index/index.twig --&gt;
&lt;h1&gt;List of available sections&lt;/h1&gt;
&lt;ul&gt;
    {% for section in sections %}
    &lt;li&gt;{{ section }}&lt;/li&gt;
    {% endfor %}
&lt;/ul&gt;
</pre>
<p style="text-align:justify;">And to finish this entry, I leave available all the code written in this post, at my <a href="https://github.com/theUniC/Zend-Framework-Twig" target="_blank"><strong>Github</strong></a> account.</p>
]]></content:encoded>
			<wfw:commentRss>http://christian.soronellas.es/2011/01/14/zend-framework-zend-view-and-twig/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Zend Framework, Zend_View y Twig</title>
		<link>http://christian.soronellas.es/2011/01/14/zend-framework-zend_view-y-twig/</link>
		<comments>http://christian.soronellas.es/2011/01/14/zend-framework-zend_view-y-twig/#comments</comments>
		<pubDate>Thu, 13 Jan 2011 22:17:17 +0000</pubDate>
		<dc:creator>Christian Soronellas</dc:creator>
				<category><![CDATA[Desarrollo web]]></category>
		<category><![CDATA[smarty]]></category>
		<category><![CDATA[smarty 2]]></category>
		<category><![CDATA[smarty 3]]></category>
		<category><![CDATA[twig]]></category>
		<category><![CDATA[zend framework]]></category>
		<category><![CDATA[zend view]]></category>
		<category><![CDATA[zend_view]]></category>

		<guid isPermaLink="false">http://christian.soronellas.es/?p=268</guid>
		<description><![CDATA[Introducción a los motores de plantillas en PHP Para contextualizar esta entrada voy a hablar un poco sobre los motores de plantillas. Los motores de plantillas son librerías que permiten abstraer todas las vistas de una aplicación buscando la máxima eficiencia y la mejor reusabilidad de código. Permiten por ejemplo, si tenemos listados de productos [...]]]></description>
			<content:encoded><![CDATA[<h2>Introducción a los motores de plantillas en PHP</h2>
<p style="text-align:justify;">Para contextualizar esta entrada voy a hablar un poco sobre los motores de plantillas. Los motores de plantillas son librerías que permiten abstraer todas las vistas de una aplicación buscando la máxima eficiencia y la mejor reusabilidad de código. Permiten por ejemplo, si tenemos listados de productos en diferentes categorizaciones, definir una UI común para las categorías qué lo precisen. Esto dota a la aplicación de mucha flexibilidad, y le da sentido a la <strong>V</strong> de <strong>MVC</strong>. Todo ello gracias a el control sobre la <a href="http://es2.php.net/manual/es/book.outcontrol.php" target="_blank">salida</a> que proporciona PHP (cosa qué, por ejemplo, era imposible con el antiguo ASP).</p>
<p style="text-align:justify;">En PHP existen multitud de motores de plantillas, si realizamos una <strong><a href="http://www.google.com/search?sourceid=chrome&#038;ie=UTF-8&#038;q=php+template+engine" target="_blank">búsqueda</a></strong> en google lo podremos comprobar. Pero básicamente, el <i>standard de facto</i> hasta ahora era <strong><a href="http://smarty.net" target="_blank">Smarty</a></strong>. Sí, sí. He dicho <strong><em>era</em></strong>. Puesto que a fecha de hoy han salido otros motores de plantillas que, bajo mi punto de vista, han puesto en entredicho que Smarty sea el motor de plantillas de PHP por excelencia. Uno de ellos, y voy a mencionar el objeto de esta entrada, es <a href="http://www.twig-project.org" target="_blank"><strong>Twig</strong></a>.</p>
<h2>Smarty 3 vs Twig</h2>
<h3>Porqué no usar Smarty 3</h3>
<p style="text-align:justify"><strong>Todo sea dicho</strong>. Smarty és una gran librería para la separación de la vista con la lógica de la aplicación. Cumple su función y la cumple con creces. Sin embargo, su segunda versión quedó desfasada con la salida de PHP 5 y su nuevo modelo de gestión de objetos. Es por ello, que hace poco que ha salido <a href="http://www.smarty.net/v3_overview" target="_blank">Smarty 3</a>. Entre las nuevas características de Smarty 3, sumadas a las que se mantienen de versión Smarty 2, podemos destacar:</p>
<ul style="margin-left:25px;">
<li>Reescrito para PHP5</li>
<li>Un analizador real para su sintaxis (su anterior versión no tenia)</li>
<li>Herencia de plantillas</li>
<li>Autoescaping de variables</li>
<li>Definición de funciones en contexto de plantilla</li>
</ul>
<p style="text-align:justify;">Y estas son solo por mencionar algunas, pues hay más. Quizá ahora la pregunta sea, y qué tiene de malo? Al parecer todo lo dicho hasta ahora tiene buena pinta. Pero y la <strong>performance</strong>? Cómo va afectar al rendimiento de nuestra aplicación la inclusión de uno u otro motor? Pues la verdad que para responder a esta pregunta recomiendo la lectura de un artículo de Fabien Potencier, <a href="http://fabien.potencier.org/article/34/templating-engines-in-php" target="_blank"><strong>dónde establece una comparativa de motores de plantillas en PHP</strong></a>, y qué cada uno seque sus propias conclusiones. Al fin y al cabo, los proyectos los acaba conociendo uno mismo y uno mismo sabe qué conviene según el caso. <strong>Yo me quedo con Twig.</strong></p>
<h3>Por qué sí usar Twig</h3>
<p style="text-align:justify;">En primer lugar, y cómo ya he mencionado antes, por motivos de rendimiento. Tal y cómo demuestra Fabien Potencier en su artículo hay diferencia de rendimiento entre los dos motores. Pero más allá de eso, la decisión a decantarse por este componente puede implicar otros aspectos del mismo. Con lo cuál, lo que viene a continuación es más a nivel de mi propia opinión (no lo declaro cómo estándar industrial).</p>
<p style="text-align:justify;">En segundo lugar, Este motor tiene ciertas carácterísticas ya desarrolladas qué no vienen de serie en Smarty. Una de ellas y tengo que decir que personalmente me gusta mucho, es el modo <strong>Sandbox</strong>. El modo Sandbox, permite restringir <strong>qué características se le permite usar al editor de las plantillas.</strong>. Me refiero a, si yo no quiero que el <em>web designer</em> pueda usar la estructura <em>if</em>, mediante el modo <em><strong>Sandbox</strong></em> de Twig no la va a poder usar. Y eso con cualquier carácteristica del motor, incluso se pueden restringir nuestras propias clases de modelo. <strong>Impresionante</strong>.</p>
<p style="text-align:justify;">Por tercer y último lugar, <strong>me gusta más el modelo de extensibilidad de Twig qué el de Smarty</strong>. Considero qué es más fácil de añadir funcionalidades a Twig. Smarty, en su versión 3, <strong>aún trae consigo el modelo de plugins de Smarty 2</strong> y sinceramente, con PHP 5.3 actualmente en alza, hecho en falta un modelo de extensibilidad más orientado a objetos.</p>
<h2>Zend_View y su agnosticismo</h2>
<p style="text-align:justify;">Digo <strong>agnosticismo</strong> puesto qué es una de las virtudes de este componente. <strong>Zend_View</strong> es agnóstico en cuánto a <em>template engine</em> se refiere, a través de la interface <em>Zend_View_Interface</em>, siendo PHP propiamente el <em>template engine</em> por defecto. Y así será cómo en este artículo voy a ilustrar cómo implementar Twig cómo extensión de Zend_View y sobreescribir la instancia por defecto de Zend_View por nuestra implementación a través de la (ya conocida :) clase abstracta Zend_Application_Resource_ResourceAbstract.</p>
<pre>

// File located at "library/Twig/Zend/View/Twig/TwigImplementation.php
require_once 'Zend/View/Interface.php';
require_once 'Twig/Autoloader.php';

class Twig_Zend_View_Twig_TwigImplementation
    implements Zend_View_Interface
{
	/**
	 * The twig loader instance
	 * @var Twig_Environment
	 */
	protected $_twigEnv;

	/**
	 * The twig loader instance
	 * @var Twig_Loader_Interface
	 */
	protected $_twigLoader;

	/**
	 * A map of all registered variables
	 * @var array
	 */
	protected $_variablesMap = array();

	/**
	 * Class constructor
	 * @param string $templateBasePath The views base path
	 * @param array $envOptions
	 */
	public function __construct($templateBasePath, array $envOptions = array())
	{
		$zendAutoloader = Zend_Loader_Autoloader::getInstance();
		$zendAutoloader -> pushAutoloader(array('Twig_Autoloader', 'autoload'));

		$this -> _twigLoader = new Twig_Loader_Filesystem($templateBasePath);
		$this -> _twigEnv = new Twig_Environment($this -> _twigLoader, $envOptions);
	}

	/**
	 * (non-PHPdoc)
	 * @see library/Zend/View/Zend_View_Interface::getEngine()
	 * @return Twig_Environment
	 */
	public function getEngine()
	{
		return $this -> _twigEnv;
	}

	/**
	 * (non-PHPdoc)
	 * @see library/Zend/View/Zend_View_Interface::setScriptPath()
	 */
	public function setScriptPath($path)
	{
	 	$this -> _twigEnv -> getLoader() -> setPaths($path);
	}

	/**
	 * (non-PHPdoc)
	 * @see library/Zend/View/Zend_View_Interface::getScriptPaths()
	 */
	public function getScriptPaths()
	{
		return $this -> _twigEnv -> getLoader() -> getPaths();
	}

	/**
	 * (non-PHPdoc)
	 * @see library/Zend/View/Zend_View_Interface::setBasePath()
	 */
	public function setBasePath($path, $classPrefix = 'Zend_View')
	{
		$this -> setScriptPath($path);
	}

	/**
	 * (non-PHPdoc)
	 * @see library/Zend/View/Zend_View_Interface::addBasePath()
	 */
	public function addBasePath($path, $classPrefix = 'Zend_View')
	{
		$this -> setScriptPath($path);
	}

	/**
	 * (non-PHPdoc)
	 * @see library/Zend/View/Zend_View_Interface::__set()
	 */
	public function __set($key, $val)
	{
		$this -> _variablesMap[$key] = $value;
	}

	/**
	 * (non-PHPdoc)
	 * @see library/Zend/View/Zend_View_Interface::__isset()
	 */
	public function __isset($key)
	{
		return isset($this -> _variablesMap[$key]);
	}

	/**
	 * (non-PHPdoc)
	 * @see library/Zend/View/Zend_View_Interface::__unset()
	 */
	public function __unset($key)
	{
		unset($this -> _variablesMap[$key]);
	}

	/**
	 * (non-PHPdoc)
	 * @see library/Zend/View/Zend_View_Interface::assign()
	 */
	public function assign($key, $value = NULL)
	{
		if (!is_null($value)) {
			$this -> _variablesMap[$key] = $value;
		} elseif (is_array($key)) {
			$this -> _variablesMap = array_merge($this -> _variablesMap, $key);
		}
	}

	/**
	 * (non-PHPdoc)
	 * @see library/Zend/View/Zend_View_Interface::clearVars()
	 */
	public function clearVars()
	{
		$this -> _variablesMap = array();
	}

	/**
	 * (non-PHPdoc)
	 * @see library/Zend/View/Zend_View_Interface::render()
	 */
	public function render($name)
	{
		$template = $this -> _twigEnv -> loadTemplate($name);
		return $template -> render($this -> _variablesMap);
	}
}
</pre>
<p style="text-align:justify;">Está clase nos va a servir para introducir Twig en el contexto de <strong>Zend Application</strong>, cómo implementación de Zend_View_Interface. Ahora el siguiente paso es sobreescribir la instancia de Zend_View en tiempo de ejecución. Y eso lo podemos llevar a cabo creando una clase que herede de <strong>Zend_Application_Resource_ResourceAbstract</strong>.</p>
<pre>

// File located at "library/Twig/Zend/View/Twig/Twig.php"
require_once 'Zend/Application/Resource/ResourceAbstract.php';
require_once 'Twig/Zend/View/Twig/TwigImplementation.php';

defined('DS')
    || define('DS', DIRECTORY_SEPARATOR);

class Twig_Zend_View_Twig_Twig
    extends Zend_Application_Resource_ResourceAbstract
{
	/**
	 * The Zend_View_TwigImplementation instance
	 * @var Zend_View_TwigImplementation
	 */
	protected $_view;

	/**
	 * (non-PHPdoc)
	 * @see library/Zend/Application/Resource/Zend_Application_Resource_Resource::init()
	 */
	public function init()
	{
		return $this -> _getView();
	}

	/**
	 * Returns the Zend_View_TwigImplementationInstance. If not initialized,
	 * initializes the instance
	 */
	protected function _getView()
	{
		if (null === $this -> _view)
		{
			$options = $this -> getOptions();
			$view = new Twig_Zend_View_Twig_TwigImplementation(APPLICATION_PATH . DS . 'views' . DS . 'scripts', $options);
			Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer')
                -> setView($view)
                -> setViewSuffix('twig');

			$this -> _view = $view;
		}

		return $this -> _view;
	}
}
</pre>
<p style="text-align:justify;">A través de la llamada a <em>setView</em> del helper <em>viewRenderer</em> se va a sobreescribir la instancia de Zend_View por nuestra implementación, previamente instanciada y además también le notificamos qué nuestras vistas tendrán la extensión <em>.twig</em>. Luego sólo falta modificar nuestro <em>application.ini</em> para poder empezar a usar el motor.</p>
<pre>
; ...
; Twig config
pluginPaths.Twig_Zend_View_Twig_ = "Twig/Zend/View/Twig/"
resources.twig.cache = APPLICATION_PATH "/../cache/twig"
</pre>
<p style="text-align:justify">Ya ahora renombramos nuestras vistas, de index.phtml a index.twig</p>
<pre>
&lt;!-- views/scripts/index/index.twig --&gt;
&lt;h1&gt;List of available sections&lt;/h1&gt;
&lt;ul&gt;
    {% for section in sections %}
    &lt;li&gt;{{ section }}&lt;/li&gt;
    {% endfor %}
&lt;/ul&gt;
</pre>
<p style="text-align:justify;">Y ya para finalizar este artículo, dejo disponible todo el código de este artículo, en mi cuenta de <a href="https://github.com/theUniC/Zend-Framework-Twig" target="_blank"><strong>Github</strong></a></p>
]]></content:encoded>
			<wfw:commentRss>http://christian.soronellas.es/2011/01/14/zend-framework-zend_view-y-twig/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Zend Framework and Doctrine 2 CLI integration</title>
		<link>http://christian.soronellas.es/2011/01/05/zend-framework-and-doctrine-2-cli-integration/</link>
		<comments>http://christian.soronellas.es/2011/01/05/zend-framework-and-doctrine-2-cli-integration/#comments</comments>
		<pubDate>Wed, 05 Jan 2011 19:36:27 +0000</pubDate>
		<dc:creator>Christian Soronellas</dc:creator>
				<category><![CDATA[Web development]]></category>
		<category><![CDATA[doctrine]]></category>
		<category><![CDATA[doctrine 2]]></category>
		<category><![CDATA[doctrine cli]]></category>
		<category><![CDATA[zend]]></category>
		<category><![CDATA[zend framework]]></category>
		<category><![CDATA[zend tool]]></category>

		<guid isPermaLink="false">http://christian.soronellas.es/?p=226</guid>
		<description><![CDATA[CLI Environtment introduction The CLI environtments are environtments executed directly on the OS shell. It&#8217;s name, CLI, is an acronym of Command Line Interface and are used for specific tasks execution. For this case, both tools have their own CLI tool: the Zend Tool by Zend Framework and the Doctrine CLI by Doctrine 2. Both [...]]]></description>
			<content:encoded><![CDATA[<h2>CLI Environtment introduction</h2>
<p><a href="http://christian.soronellas.es/wp-content/uploads/2010/12/doctrine_logo.jpg"><img style="border:none;" src="http://christian.soronellas.es/wp-content/uploads/2010/12/doctrine_logo.jpg" alt="" title="Doctrine Project" width="200" height="42" class="alignleft size-full wp-image-193" /></a>
<p style="text-align: justify;">The CLI environtments are environtments executed directly on the OS shell. It&#8217;s name, <em>CLI</em>, is an acronym of <em>Command Line Interface</em> and are used for specific tasks execution. For this case, both tools have their own CLI tool: the <strong>Zend Tool</strong> by <strong>Zend Framework</strong> and the <strong>Doctrine CLI</strong> by Doctrine 2. Both CLI tools, are intended for code generation and for agilize web application maintenance tasks. For example: the creation of a Zend Framework application with its specific layout, the generation of the different domain model classes of Zend_Db by the <strong>Zend Tool</strong> or the Doctrine 2 entities, repositories and proxies generation.</p>
<h2>Firsts steps. Understanding Zend Tool internals</h2>
<p style="text-align: justify;">Zend Tool, consists of several components to make easier the task integration on its context. On one hand there is the <strong>Zend_Tool_Framework</strong> family components which broadly provides the integration of web application independent tasks. For example, If we have to design a task that provides an entrypoint to the system cron without using web application resources, probably the best way will be using the <strong>Zend_Tool_Framework</strong>. However, if the task, we have to design, depends in some point on a resource of the web application, sure It will need to know about web application aspects. And this can be done with the <strong>Zend_Tool_Project</strong> family components (wich is the component that I will use, right <em>here</em> and right <em>now</em>).</p>
<p style="text-align: justify;">Once the tasks have been designed and implemented, <em>Zend Tool</em> must be noticed about of its presence by the <em>.zf.ini</em> file, located on the user home.</p>
<h2>Music, maestro!</h2>
<p style="text-align:justify;">On this post I&#8217;m going to describe, the creation of two tasks that will be linked to a <strong>Zend Framework</strong> web application with <strong>Doctrine 2</strong> integrated as <em>O/RM</em>. This two tasks, will be responsible primarily to configure the <strong>Zend Application</strong> to be able to execute Doctrine 2 without problems (I have explained how on my previous post, you can check it a <a href="/2010/11/20/zend-framework-y-doctrine-2/?lang=en">here</a>) and to generate several useful files for its execution (<a href="http://www.doctrine-project.org/projects/orm/2.0/docs/reference/configuration/en#proxy-objects" target="_blank">proxies</a> and <a href="http://www.doctrine-project.org/projects/orm/2.0/docs/reference/working-with-objects/en#querying:custom-repositories" target="_blank">repositories</a>).</p>
<p style="text-align:justify;">Analyzing a bit the <strong>Zend Tool Project</strong> and the <strong>Doctrine 2 CLI</strong> architecture we are going to write an abstract class that will be useful to <em>prepare</em> all the <strong>Doctrine 2</strong> environment and it can be extended to create diferent provider tasks.</p>
<pre>
&lt;?php
/**
 * File located at /library/Doctrine/Zend/Tool/Project/Provider/Abstract.php
 */

require_once &#039;Zend/Tool/Project/Provider/Abstract.php&#039;;
require_once &#039;Doctrine/Common/ClassLoader.php&#039;;

abstract class Doctrine_Zend_Tool_Project_Provider_Abstract
    extends Zend_Tool_Project_Provider_Abstract
{
    /**
     * A class property to hold the Zend_Tool_Project_Profile instance.
     * @var Zend_Tool_Project_Profile
     */
    protected $_profile;

    /**
     * The application.ini config file
     * @var Zend_Config_Ini
     */
    protected $_config;

    /**
     * The path to the application.ini
     * @var string
     */
    protected $_appConfigFilePath;

    /**
     * The path to the application directory
     * @var string
     */
    protected $_appPath;

    /**
     * The target section of the application.ini we want to work on
     * @var string
     */
    protected $_sectionName;

    /**
     * The Doctrine CLI instance, ready to execute tasks
     * @var Symfony\Component\Console\Application
     */
    protected $_doctrineCli = NULL;

    /**
     * Prepares Doctrine 2 for task performing, with the application.ini stuff
     * @return \Symfony\Component\Console\Application $cli
     */
    protected function _prepare($sectionName = &#039;production&#039;)
    {
    	if (is_null($this -&gt; _doctrineCli)) {
    		// Load the project profile (.zfproject.xml)
	        $this -&gt; _profile = $this -&gt; _loadProfile(self::NO_PROFILE_THROW_EXCEPTION);
	        $appConfigFileResource = $this -&gt; _profile -&gt; search(&#039;applicationConfigFile&#039;);

	        if ($appConfigFileResource == FALSE) {
	            throw new Zend_Tool_Project_Exception(&#039;A project with an application config file is required to use this provider.&#039;);
	        }

	        $this -&gt; _appConfigFilePath = $appConfigFileResource -&gt; getPath();

	        $appDirResource = $this -&gt; _profile -&gt; search(&#039;applicationDirectory&#039;);
	        $this -&gt; _appPath = $appDirResource -&gt; getPath();

	        // This define it&#039;s important in order to work with the application.ini, since it&#039;s paths are configured
	        // with the APPLICATION_PATH constants. So define it just before instance the Zend_Config_Ini.
	        define(&#039;APPLICATION_PATH&#039;, $this -&gt; _appPath);
	        $this -&gt; _config = new Zend_Config_Ini($this -&gt; _appConfigFilePath);

	        $this -&gt; _sectionName = $sectionName;

	        if (!isset($this -&gt; _config -&gt; {$this -&gt; _sectionName})) {
	            throw new Zend_Tool_Project_Exception(&#039;The config does not have a &#039; . $this -&gt; _sectionName . &#039; section.&#039;);
	        }

	        /**
	         * Maybe at this point doctrine isn&#039;t configured on the application.ini, do all this stuff only if
	         * configured
	         */
	        if (isset($this -&gt; _config -&gt; {$this -&gt; _sectionName} -&gt; resources -&gt; doctrine)) {
		        $doctrineConsoleHelperSet = $this -&gt; _getDoctrineConsoleHelperSet();
		        $this -&gt; _doctrineCli = new \Symfony\Component\Console\Application(&#039;Doctrine Command Line Interface&#039;, Doctrine\ORM\Version::VERSION);
				$this -&gt; _doctrineCli -&gt; setCatchExceptions(TRUE);
				$this -&gt; _doctrineCli -&gt; setHelperSet($doctrineConsoleHelperSet);
				$this -&gt; _doctrineCli -&gt; addCommands(array(
				    new \Doctrine\DBAL\Tools\Console\Command\RunSqlCommand(),
				    new \Doctrine\DBAL\Tools\Console\Command\ImportCommand(),
				    new \Doctrine\ORM\Tools\Console\Command\ClearCache\MetadataCommand(),
				    new \Doctrine\ORM\Tools\Console\Command\ClearCache\ResultCommand(),
				    new \Doctrine\ORM\Tools\Console\Command\ClearCache\QueryCommand(),
				    new \Doctrine\ORM\Tools\Console\Command\SchemaTool\CreateCommand(),
				    new \Doctrine\ORM\Tools\Console\Command\SchemaTool\UpdateCommand(),
				    new \Doctrine\ORM\Tools\Console\Command\SchemaTool\DropCommand(),
				    new \Doctrine\ORM\Tools\Console\Command\EnsureProductionSettingsCommand(),
				    new \Doctrine\ORM\Tools\Console\Command\ConvertDoctrine1SchemaCommand(),
				    new \Doctrine\ORM\Tools\Console\Command\GenerateRepositoriesCommand(),
				    new \Doctrine\ORM\Tools\Console\Command\GenerateEntitiesCommand(),
				    new \Doctrine\ORM\Tools\Console\Command\GenerateProxiesCommand(),
				    new \Doctrine\ORM\Tools\Console\Command\ConvertMappingCommand(),
				    new \Doctrine\ORM\Tools\Console\Command\RunDqlCommand(),
				    new \Doctrine\ORM\Tools\Console\Command\ValidateSchemaCommand()
				));

				return $this -&gt; _doctrineCli;
			}
		}
    }

    /**
     * Builds the Doctrine 2 Entity Manager object, and the helper set, needed by the
     * Doctrine 2 Console.
     * @return \Symfony\Component\Console\Helper\HelperSet $helperSet
     */
    private function _getDoctrineConsoleHelperSet()
    {
    	$classLoader = new \Doctrine\Common\ClassLoader(&#039;Doctrine&#039;);
		$classLoader-&gt;register();

		$classLoader = new \Doctrine\Common\ClassLoader(&#039;Symfony&#039;, &#039;Doctrine&#039;);
		$classLoader-&gt;register();

    	$classLoader = new \Doctrine\Common\ClassLoader(&#039;Application\Models&#039;, dirname(APPLICATION_PATH));
		$classLoader-&gt;register();

		$classLoader = new \Doctrine\Common\ClassLoader(&#039;Application\Proxies&#039;, dirname(APPLICATION_PATH));
		$classLoader-&gt;register();

		$classLoader = new \Doctrine\Common\ClassLoader(&#039;Application\Repositories&#039;, dirname(APPLICATION_PATH));
        $classLoader-&gt;register();

		$entityManager = $this -&gt; _buildDoctrineEntityManager();
		return new \Symfony\Component\Console\Helper\HelperSet(array(
            &#039;db&#039; =&gt; new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($entityManager-&gt;getConnection()),
            &#039;em&#039; =&gt; new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($entityManager)
        ));
    }

    /**
     * Builds the EntityManager for Doctrine 2
     * @return \Doctrine\ORM\EntityManager
     */
    private function _buildDoctrineEntityManager()
    {
    	$config = new \Doctrine\ORM\Configuration();
		$cache = new \Doctrine\Common\Cache\ArrayCache();
		$config -&gt; setMetadataCacheImpl($cache);
		$config -&gt; setMetadataDriverImpl(\Doctrine\ORM\Mapping\Driver\AnnotationDriver::create(array(
            $this -&gt; _config -&gt; {$this -&gt; _sectionName} -&gt; resources -&gt; doctrine -&gt; entitiesPath
		)));
		$config -&gt; setProxyDir($this -&gt; _config -&gt; {$this -&gt; _sectionName} -&gt; resources -&gt; doctrine -&gt; proxiesPath);
		$config -&gt; setProxyNamespace(&#039;Application\Proxies&#039;);
		$config -&gt; setAutoGenerateProxyClasses(TRUE);

		return \Doctrine\ORM\EntityManager::create($this -&gt; _config -&gt; {$this -&gt; _sectionName} -&gt; resources -&gt; doctrine -&gt; connection -&gt; toArray(), $config);
    }

    /**
     * This method will be responsible for running any task on the Doctrine 2 CLI
     * Usage:
     *
     *     $this -&gt; _run(array(
     *         &#039;command&#039; =&gt; &#039;orm:generate-entities&#039;,
     *         &#039;dest-path&#039; =&gt; &#039;/application/models&#039;
     *     ), &#039;production&#039;);
     *
     * @param array $arguments The task arguments
     * @param string $sectionName
     * @throws Zend_Tool_Project_Exception
     */
    protected function _run(array $arguments, $sectionName = &#039;production&#039;)
    {
    	if (is_null($this -&gt; _doctrineCli)) {
            $doctrineCli = $this -&gt; _prepare($sectionName);
    	} else {
    		$doctrineCli = $this -&gt; _doctrineCli;
    	}

        if (!is_null($doctrineCli)) {
            $consoleOutput = new \Symfony\Component\Console\Output\ConsoleOutput();
            $consoleOutput -&gt; setDecorated(TRUE);
            $doctrineCli -&gt; run(new \Symfony\Component\Console\Input\ArrayInput($arguments), $consoleOutput);
        } else {
        	throw new Zend_Tool_Project_Exception(&#039;Doctrine has not been configured on this project. Run first, the task configure on the doctrine-config provider.&#039;);
        }
    }
}
</pre>
<p style="text-align:justify;">This abstract class will allow us to execute Doctrine 2 CLI tasks by the options defined on the <em>application.ini</em> file. So then, we define the following tasks</p>
<h3>Provider to configure Doctrine 2</h3>
<pre>
&lt;?php

/**
 * File &#039;Doctrine/Zend/Tool/Project/Provider/DoctrineConfigProvider.php
 */
require_once &#039;Doctrine/Zend/Tool/Project/Provider/Abstract.php&#039;;

class Doctrine_Zend_Tool_Project_Provider_DoctrineConfigProvider
    extends Doctrine_Zend_Tool_Project_Provider_Abstract
{
	/**
	 * This task configures Doctrine environtment on the application.ini.
	 * Usage:
	 *
	 *     &gt; zf config doctrine-provider \
	 *       &#039;connection[driver]=pdo_sqlite&amp;connection[path]=APPLICATION_PATH &quot;/../data/db/database-dev&quot;&#039; \
	 *       development
	 *
	 * The available key configurations are as follows:
	 *     &middot; connection: an array with all the key configs needed to configure a doctrine dbal connection
	 *       see http://www.doctrine-project.org/projects/dbal/2.0/docs/reference/configuration/en#configuration for more info
	 *     &middot; entitiesPath: The path where entities will reside
	 *     &middot; proxiesPath: The path where proxies will reside
	 *     &middot; repositoriesPath: The path where repositories will reside
	 *     &middot; cacheClass: The class used to act as a object cache (One from \Doctrine\Common\Cache)
	 * @param string $connectionQueryString
	 * @param string $sectionName
	 * @throws Zend_Tool_Project_Exception
	 */
	public function config($connectionQueryString, $sectionName = &#039;production&#039;)
	{
		$this -&gt; _prepare($sectionName);
		parse_str($connectionQueryString, $options);
		if (isset($options[&#039;connection&#039;]) &amp;&amp; isset($options[&#039;connection&#039;][&#039;driver&#039;]) &amp;&amp; method_exists($this, &quot;_{$options[&#039;connection&#039;][&#039;driver&#039;]}&quot;)) {
			$method = &quot;_{$options[&#039;connection&#039;][&#039;driver&#039;]}&quot;;
			$this -&gt; $method($options, $sectionName);
		} else {
			throw new Zend_Tool_Project_Exception(&#039;Unsupported driver (&#039; . $options[&#039;connection&#039;][&#039;driver&#039;] . &#039;)&#039;);
		}
	}

	/**
	 * A method to configure the connection to the database. To implement more connections,
	 * define for exemple &quot;_pdo_mysql&quot; or &quot;_pdo_pgsql&quot; with the same signature as this method.
	 * This method only validates the options of the connection. The real implementation is on
	 * the &quot;_setConfig&quot; method.
	 * @param array $options The options defined
	 * @param unknown_type $sectionName
	 * @throws Zend_Tool_Project_Exception
	 */
	protected function _pdo_sqlite(array $options, $sectionName = &#039;production&#039;)
	{
		// Build the options array
		if (!isset($options[&#039;connection&#039;][&#039;path&#039;]) &amp;&amp; !isset($options[&#039;connection&#039;][&#039;memory&#039;])) {
            throw new Zend_Tool_Project_Exception(&#039;Malformed connection string&#039;);
        }

        $this -&gt; _setConfig($options, $sectionName);
	}

	/**
	 * This method serializes all the config options from Doctrine 2 CLI to the
	 * application.ini
	 * @param array $options The defined options
	 * @param string $sectionName
	 */
	protected function _setConfig(array $options, $sectionName = &#039;production&#039;)
	{
		$doctrineItem = array(
            &#039;resources&#039; =&gt; array(
                &#039;doctrine&#039; =&gt; array()
            )
        );

        $doctrineItem[&#039;resources&#039;][&#039;doctrine&#039;][&#039;entitiesPath&#039;] = isset($options[&#039;entitiesPath&#039;]) ? $options[&#039;entitiesPath&#039;] : &#039;APPLICATION_PATH &quot;/models&quot;&#039;;
        $doctrineItem[&#039;resources&#039;][&#039;doctrine&#039;][&#039;proxiesPath&#039;] = isset($options[&#039;proxiesPath&#039;]) ? $options[&#039;proxiesPath&#039;] : &#039;APPLICATION_PATH &quot;/proxies&quot;&#039;;
        $doctrineItem[&#039;resources&#039;][&#039;doctrine&#039;][&#039;repositoriesPath&#039;] = isset($options[&#039;repositoriesPath&#039;]) ? $options[&#039;repositoriesPath&#039;] : &#039;APPLICATION_PATH &quot;/repositories&quot;&#039;;
        $doctrineItem[&#039;resources&#039;][&#039;doctrine&#039;][&#039;cacheClass&#039;] = isset($options[&#039;cacheClass&#039;]) ? $options[&#039;cacheClass&#039;] : &#039;Doctrine\Common\Cache\ApcCache&#039;;
        $doctrineItem[&#039;resources&#039;][&#039;doctrine&#039;][&#039;connection&#039;] = $options[&#039;connection&#039;];
        $appConfigFileResource = $this -&gt; _profile -&gt; search(&#039;applicationConfigFile&#039;);
        $appConfigFileResource -&gt; addItem($doctrineItem, $sectionName, NULL);
        $appConfigFileResource -&gt; create();
        $this -&gt; _registry -&gt; getResponse() -&gt; appendContent(&quot;A new Doctrine 2 configuration for the section $sectionName, has been stablished.&quot;);
	}
}
</pre>
<h3>Entities, Proxies and Repositories generation Provider</h3>
<pre>
&lt;?php

/**
 * File /Doctrine/Zend/Tool/Project/Provider/DoctrineOrmProvider.php
 */
require_once &#039;Doctrine/Zend/Tool/Project/Provider/Abstract.php&#039;;

class Doctrine_Zend_Tool_Project_Provider_DoctrineOrmProvider
    extends Doctrine_Zend_Tool_Project_Provider_Abstract
{
	/**
	 * A task to generate the entity repositories on a defined path
	 * @param string $destPath
	 * @param string $sectionName
	 */
	public function generateRepositories($destPath, $sectionName = &#039;production&#039;)
	{
		$this -&gt; _run(array(
            &#039;command&#039; =&gt; &#039;orm:generate-repositories&#039;,
            &#039;dest-path&#039; =&gt; $destPath
		));
	}

	/**
	 * A task to generate proxies on a defined path
	 * @param string $destPath
	 * @param string $sectionName
	 */
	public function generateProxies($destPath, $sectionName = &#039;production&#039;)
	{
		$this -&gt; _run(array(
            &#039;command&#039; =&gt; &#039;orm:generate-proxies&#039;,
            &#039;dest-path&#039; =&gt; $destPath
		));
	}

	/**
	 * A task to generate entities on a defined path
	 * @param string $destPath
	 * @param string $sectionName
	 */
    public function generateEntities($destPath, $sectionName = &#039;production&#039;)
    {
        $this -&gt; _run(array(
            &#039;command&#039; =&gt; &#039;orm:generate-entities&#039;,
            &#039;dest-path&#039; =&gt; $destPath
        ));
    }
}
</pre>
<h2>Concluding</h2>
<p style="text-align:justify">The only thing to do from here, is to notice the <strong>Zend Tool</strong> about the presence of this tasks in our CLI environment. For this, as I said before, we&#8217;re going to use the &#8220;.zf.ini&#8221; file, located on our user&#8217;s home directory. We edit this file and update the  <em>include_path</em> to point to the <em>library</em> directory of our project and also add the recently created classes.</p>
<pre>
php.include_path = ".:/path/to/my/zend/framework/project/library:/usr/local/zend/share/pear"
basicloader.classes.0 = "Doctrine_Zend_Tool_Project_Provider_DoctrineConfigProvider"
basicloader.classes.1 = "Doctrine_Zend_Tool_Project_Provider_DoctrineOrmProvider"
</pre>
<p style="text-align:justify;">With this we should be able to execute Doctrine 2 <strong>CLI</strong> tasks, by the <strong>Zend Tool</strong>.</p>
]]></content:encoded>
			<wfw:commentRss>http://christian.soronellas.es/2011/01/05/zend-framework-and-doctrine-2-cli-integration/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>By and for the community &#8230; here my two cents</title>
		<link>http://christian.soronellas.es/2010/12/23/by-and-for-the-community-here-my-two-cents/</link>
		<comments>http://christian.soronellas.es/2010/12/23/by-and-for-the-community-here-my-two-cents/#comments</comments>
		<pubDate>Wed, 22 Dec 2010 23:39:20 +0000</pubDate>
		<dc:creator>Christian Soronellas</dc:creator>
				<category><![CDATA[Community @en]]></category>
		<category><![CDATA[Web development]]></category>
		<category><![CDATA[community]]></category>
		<category><![CDATA[github]]></category>

		<guid isPermaLink="false">http://christian.soronellas.es/?p=238</guid>
		<description><![CDATA[I&#8217;ve decided to release the code exposed here on my posts. For this, I&#8217;ll use my Github account to put, in a repositories way, all the code. At the moment there is only available the first post code about Zend Framework and Doctrine 2. For those of you interested, feel free to download and use [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align:justify;">I&#8217;ve decided to release the code exposed here on my posts. For this, I&#8217;ll use my <a href="http://github.com/theUniC" target="_blank">Github</a> account to put, in a repositories way, all the code. At the moment there is only available the first post code about <strong>Zend Framework</strong> and <strong>Doctrine 2</strong>. For those of you interested, feel free to download and use it. I hope to contribute my bit to the community.</p>
<ul style="margin-left:30px;">
<li><a href="https://github.com/theUniC/Zend-Framework-Doctrine2" target="_blank">Zend Framework and Doctrine 2</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://christian.soronellas.es/2010/12/23/by-and-for-the-community-here-my-two-cents/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Por y para la comunidad … e aquí mi granito de arena</title>
		<link>http://christian.soronellas.es/2010/12/23/por-y-para-la-comunidad-e-aqui-mi-granito-de-arena/</link>
		<comments>http://christian.soronellas.es/2010/12/23/por-y-para-la-comunidad-e-aqui-mi-granito-de-arena/#comments</comments>
		<pubDate>Wed, 22 Dec 2010 23:21:46 +0000</pubDate>
		<dc:creator>Christian Soronellas</dc:creator>
				<category><![CDATA[Comunidad]]></category>
		<category><![CDATA[Desarrollo web]]></category>
		<category><![CDATA[comunidad]]></category>
		<category><![CDATA[github]]></category>

		<guid isPermaLink="false">http://christian.soronellas.es/?p=233</guid>
		<description><![CDATA[He decidido liberar el código que expongo aquí en mis entradas. Para ello, voy a hacer uso de mi cuenta en Github para ir colgando en forma de repositorios el código qué aquí vaya exponiendo. De momento hay disponible el código de la primera entrada de Zend Framework y Doctrine 2. Para quién le interese [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align:justify;">He decidido liberar el código que expongo aquí en mis entradas. Para ello, voy a hacer uso de mi cuenta en <a href="http://github.com/theUniC" target="_blank">Github</a> para ir colgando en forma de repositorios el código qué aquí vaya exponiendo. De momento hay disponible el código de la primera entrada de <strong>Zend Framework</strong> y <strong>Doctrine 2</strong>. Para quién le interese es libre de bajarse el código y usarlo. Espero así aportar mi granito de arena a la comunidad.</p>
<ul style="margin-left:30px;">
<li><a href="https://github.com/theUniC/Zend-Framework-Doctrine2" target="_blank">Zend Framework y Doctrine 2</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://christian.soronellas.es/2010/12/23/por-y-para-la-comunidad-e-aqui-mi-granito-de-arena/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

