<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Francisco Ugalde]]></title><description><![CDATA[Software Engineer, amante de la tecnología, la arquitectura de software y de compartir tips y contenido de valor. Siéntete libre de contactarme vía [email](mail]]></description><link>https://franciscougalde.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1628509179266/ML6CHUYzB.png</url><title>Francisco Ugalde</title><link>https://franciscougalde.com</link></image><generator>RSS for Node</generator><lastBuildDate>Tue, 14 Apr 2026 09:03:28 GMT</lastBuildDate><atom:link href="https://franciscougalde.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[12 características fascinantes de HTML que probablemente no conocías]]></title><description><![CDATA[HTML representa uno de los pilares fundamentales en el desarrollo web. Sin embargo, hoy en día, el avance de la tecnología, en pro de separar el proceso en "capas" por llamarlo de alguna manera, ha permitido la aparición de las hojas de estilos (CSS)...]]></description><link>https://franciscougalde.com/12-caracteristicas-fascinantes-de-html-que-probablemente-no-conocias</link><guid isPermaLink="true">https://franciscougalde.com/12-caracteristicas-fascinantes-de-html-que-probablemente-no-conocias</guid><category><![CDATA[HTML5]]></category><category><![CDATA[Programming Tips]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[webdev]]></category><category><![CDATA[HTML]]></category><dc:creator><![CDATA[Francisco Ugalde]]></dc:creator><pubDate>Sat, 25 Sep 2021 13:47:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1632577604210/pClbXIXdn.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>HTML</strong> representa uno de los pilares fundamentales en el desarrollo web. Sin embargo, hoy en día, el avance de la tecnología, en pro de separar el proceso en "<strong>capas</strong>" por llamarlo de alguna manera, ha permitido la aparición de las <strong>hojas de estilos</strong> (<strong>CSS</strong>) y <strong>Javascript</strong> (<strong>JS</strong>), permitiendo de cierta manera que <strong>HTML</strong> pierda parte de su potencial.</p>
<p>Sin embargo, <strong>HTML</strong> ha continuado su evolución y pues en este post quiero mostrarte una lista de sus atributos que probablemente no conoces, pero que pueden ser super útiles.</p>
<blockquote>
<p>Si consideras que me he olvidado de algún otro atributo o característica importante, déjame saber en los comentarios y lo incluiré en el post. 😉</p>
</blockquote>
<h2 id="1-atributo-multiple">1.- Atributo: multiple</h2>
<p>El atributo "<strong>multiple</strong>"  nos permite indicarle a un campo input que puede aceptar múltiples valores por lo que el usuario podrá ingresar múltiples valores por ejemplo en un . </p>
<p>Es un atributo "<strong>boolean</strong>" válido para tipos de entrada de correo electrónico (<strong>email</strong>) o archivo (<strong>file</strong>) y el elemento .</p>
<p>Para el caso de un input de tipo "<strong>email</strong>", si y solo si, se especifica el atributo "<strong>multiple</strong>", el valor puede ser una lista de direcciones de correo electrónico separadas por comas. Cualquier espacio en blanco será removido de cada email en la lista.</p>
<p>Para la entrada de un archivo, el usuario puede seleccionar varios archivos en la forma habitual (<strong>manteniendo presionada la tecla Mayús o Crtl</strong>).</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"file"</span> <span class="hljs-attr">multiple</span>&gt;</span>
</code></pre>
<h2 id="2-atributo-accept">2.- Atributo: accept</h2>
<p>El elemento  tiene el atributo "<strong>accept</strong>" el cual te permite indicarle al usuario los tipos de archivos permitidos que se pueden cargar.</p>
<p>Solo debemos pasarle una cadena de texto que contenga la lista separada por comas, los formatos de archivos permitidos.</p>
<p>También puede usarlo para especificar solo formato de audio, imagen o video.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span> = <span class="hljs-string">"file"</span> <span class="hljs-attr">accept</span> = <span class="hljs-string">". png, .jpg"</span>&gt;</span>
</code></pre>
<h2 id="3-atributo-contenteditable">3.- Atributo: contenteditable</h2>
<p>"<strong>contenteditable</strong>" es un atributo global (aplicable a todos los elementos HTML) que hace que el contenido HTML sea o no, editable por el usuario. Sin embargo, hay que tener extremo cuidad con los cambios aplicados solo en el contenido visible frente al contenido del DOM.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">contenteditable</span> = <span class="hljs-string">"true"</span>&gt;</span> Soy un div editable, 😉 <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
div editable
</code></pre>
<h2 id="4-atributo-spellcheck">4.- Atributo: spellcheck</h2>
<p>"<strong>spellcheck</strong>" es otro atributo global que puede utilizar para revisar la ortografía y la gramática en elementos HTML tales como inputs y otros elementos editables.</p>
<blockquote>
<p>Nota: Por lo general, los elementos que no son editables, no se comprueban en busqueda de errores ortográficos, aún cuando el atributo "<strong>spellcheck</strong>" esté establecido a "<strong>true</strong>" y el navegador del usuario soporta la verificación de ortografía.</p>
</blockquote>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">contenteditable</span> = <span class="hljs-string">"true"</span> <span class="hljs-attr">spellcheck</span> = <span class="hljs-string">"true"</span>&gt;</span>
Gracias por comprobar mi ortografía :)
<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<h2 id="5-atributo-translate">5.- Atributo: translate</h2>
<p>"translate" le indica al navegador si el contenido debe o no traducirse.</p>
<p>Por ejemplo, podemos usarlo para evitar que Google Translate intente traducir automáticamente el nombre de su empresa o marca.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">footer</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">translate</span> = <span class="hljs-string">"no"</span>&gt;</span> Apple Company, Inc. <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">footer</span>&gt;</span>
</code></pre>
<h2 id="6-atributo-poster">6.- Atributo: poster</h2>
<p>El atributo "poster" sirve exclusivamente para controles de video y nos permite asignar una imagen para que sea mostrada mientras se descarga el video o hasta que el usuario presione el botón de reproducción.</p>
<p>Si no se especifica una imagen, entonces no se mostrará nada hasta que el primer fotograma esté disponible, es entonces cuando se utiliza este primer fotograma como poster.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">video</span> <span class="hljs-attr">controls</span>
<span class="hljs-attr">src</span> = <span class="hljs-string">"https://stockvideos.org/video-available/8046.mp4"</span>
<span class="hljs-attr">poster</span> = <span class="hljs-string">"https://stockvideos.org/thumbnails/108046-rainbow-lorikeet-parrots-occupying-table-at.jpg"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">video</span>&gt;</span>
</code></pre>
<h2 id="7-atributo-download">7.- Atributo: download</h2>
<p>El atributo "<strong>download</strong>" combinado con un elemento <a> nos permite indicarle al navegador para que descargue una URL en lugar de "navegar" hasta ella, de modo que se solicite al usuario el destino donde desea guardar el recurso solicitado en su equipo local.</a></p>
<blockquote>
<p>Nota: También puede especificar el nombre del archivo.</p>
</blockquote>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"download.php?file=xyz.rar"</span> <span class="hljs-attr">download</span>=<span class="hljs-string">"website"</span>&gt;</span>Download Website 📦<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
</code></pre>
<h2 id="8-tag-details">8.- Tag: details</h2>
<p>El tag "<strong>details</strong>" proporciona detalles on-demand al usuario. Si necesitas mostrar contenido opcional y que sea a petición del usuario, esta etiqueta es tu mejor opción. </p>
<p>De forma predeterminada, el "<strong>widget</strong>" está cerrado. Cuando está abierto, se expande y muestra el contenido que contiene.</p>
<p>La etiqueta "<strong>summary</strong>" se usa con "<strong>details</strong>" para especificar un encabezado visible.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">details</span>&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">summary</span>&gt;</span>Click aquí para ver detalles<span class="hljs-tag">&lt;/<span class="hljs-name">summary</span>&gt;</span>
         <span class="hljs-tag">&lt;<span class="hljs-name">table</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>#<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>Producto<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>Descripción<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>Precio<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>1<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>Zapatillas Nike<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>Zapatillas Nike running para entrenamiento<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>€ 119.95<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">details</span>&gt;</span>
</code></pre>
<h2 id="9-tag-output">9.- Tag: output</h2>
<p>La etiqueta  representa el resultado de un cálculo. Normalmente, este elemento define una región que se utilizará para mostrar la salida de texto de algún cálculo.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">oninput</span>=<span class="hljs-string">"total.value=parseInt(price.value) * parseInt(quantity.value)"</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"integer"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"price"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"0"</span>&gt;</span>
          * <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"quantity"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"0"</span>&gt;</span>
                = <span class="hljs-tag">&lt;<span class="hljs-name">output</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"total"</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"price quantity"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">output</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
</code></pre>
<h2 id="10-tag-datalist">10.- Tag: datalist</h2>
<p>La etiqueta "<strong>datalist</strong>" nos permite especificar una lista de opciones predefinidas y ademas permitir a los usuarios agregar más. Proporciona una función de auto completar que le permite obtener las opciones deseadas con una escritura anticipada.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">action</span>=<span class="hljs-string">""</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"get"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"product"</span>&gt;</span>Elige tus productos de la lista:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">list</span>=<span class="hljs-string">"products"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"product"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"product"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">datalist</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"products"</span>&gt;</span>
           <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Ordenador"</span>&gt;</span>
           <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Cascos"</span>&gt;</span>
           <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Teclado"</span>&gt;</span>
           <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Ratón"</span>&gt;</span>
           <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Monitor"</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">datalist</span>&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>
 <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
</code></pre>
<h3 id="consejos">Consejos:</h3>
<blockquote>
<p>¿En qué se diferencia de la etiqueta "select" - "option" tradicional? Seleccione la etiqueta para seleccionar uno o más elementos de las opciones que necesita para ir a través de la lista para elegir. datalist es una función avanzada con soporte para auto completar.</p>
</blockquote>
<h2 id="11-tipo-range-slider">11.- Tipo: Range (Slider)</h2>
<p>El rango es un tipo de entrada que nos permite seleccionar valores utilizando un "<strong>slider</strong>". Este tipo de entrada (<strong>input</strong>) es muy útil en muchos casos como por ejemplo para seleccionar rangos de precios, filtros de distancia, entre otros.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> 
         <span class="hljs-attr">type</span>=<span class="hljs-string">"range"</span> 
         <span class="hljs-attr">name</span>=<span class="hljs-string">"kilometers"</span> 
         <span class="hljs-attr">min</span>=<span class="hljs-string">"5"</span> 
         <span class="hljs-attr">max</span>=<span class="hljs-string">"50"</span> 
         <span class="hljs-attr">step</span>=<span class="hljs-string">"5"</span> 
         <span class="hljs-attr">value</span>=<span class="hljs-string">""</span>
         <span class="hljs-attr">onchange</span>=<span class="hljs-string">"changeValue(event)"</span>/&gt;</span>
 <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
 <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"range"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">output</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"output"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"result"</span>&gt;</span>  <span class="hljs-tag">&lt;/<span class="hljs-name">output</span>&gt;</span>
 <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">changeValue</span>(<span class="hljs-params">event</span>) </span>{
            <span class="hljs-keyword">let</span> value = event.target.value;
            <span class="hljs-keyword">let</span> output = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'output'</span>);
            output.value = value;
}
</code></pre>
<h2 id="12-tag-meter">12.- Tag: meter</h2>
<p>El tag "<strong>meter</strong>" nos sirve para medir datos dentro de un rango. Nos permite mostrar como una especie de barra de progreso en base a los valores establecidos:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"shipping"</span>&gt;</span>Tracking del producto<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meter</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"shipping"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"0.6"</span>&gt;</span>Enviado!<span class="hljs-tag">&lt;/<span class="hljs-name">meter</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
</code></pre>
<p>Si te gustó el post, o te pareció interesante, piensa en que quizás le pueda servir a alguien más, sobre todo si se esta iniciando en el mundo del desarrollo web. Es por esto que sería de muchísima ayuda, tanto para esas personas, como para mi, que compartas este post. Te lo agradecería muchísimo 🤩</p>
]]></content:encoded></item><item><title><![CDATA[Value Objects en PHP]]></title><description><![CDATA[Los Value Objects  (VO) u Objetos de Valor son uno de los bloques de construcción en los principios de “Domain-Driven Design". Representan un valor y no tienen identidad. Dicho esto, dos objetos de valor son iguales si sus valores son iguales.
Otra c...]]></description><link>https://franciscougalde.com/value-objects-en-php</link><guid isPermaLink="true">https://franciscougalde.com/value-objects-en-php</guid><category><![CDATA[software architecture]]></category><category><![CDATA[DDD]]></category><category><![CDATA[PHP]]></category><category><![CDATA[software development]]></category><category><![CDATA[clean code]]></category><dc:creator><![CDATA[Francisco Ugalde]]></dc:creator><pubDate>Tue, 07 Jul 2020 13:35:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628694969458/rtygO4vWK7.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Los <strong>Value Objects </strong> (<strong>VO</strong>) u <strong>Objetos de Valor</strong> son uno de los bloques de construcción en los principios de “<a target="_blank" href="https://martinfowler.com/tags/domain%20driven%20design.html"><strong>Domain-Driven Design</strong></a>". Representan un valor y no tienen identidad. Dicho esto, dos objetos de valor son iguales si sus valores son iguales.</p>
<p>Otra característica importante es que los objetos de valor son inmutables, es decir, no se pueden modificar después de la creación.</p>
<p>La única forma válida de crear <strong>Value</strong> <strong>Objects</strong> es pasar toda la información requerida al constructor y validando dicha información en algún método interno.</p>
<p><a target="_blank" href="http://martinfowler.com/eaaCatalog/valueObject.html"><strong>Martin Fowler</strong></a> define los <strong>value</strong> <strong>objects</strong> (<strong>VO</strong>) o <strong>objetos de valor</strong> de la siguiente manera: un objeto pequeño y simple, como el dinero o un rango de fechas, cuya igualdad no se basa en la identidad.</p>
<p>Esto significa, dos objetos de valor son iguales, no cuándo se refieren al mismo objeto, sino cuándo el valor que tienen es igual.</p>
<p>Por ejemplo, dos billetes diferentes de cien dólares tienen el mismo valor cuando los usamos para comprar algo (la clase Dinero sería un objeto de valor).</p>
<p>Por otro lado, tenemos entidades que se comparan en identidad, por ejemplo: dos personas pueden tener el mismo nombre, pero no son la misma persona (la clase Persona sería una entidad), por lo tanto, no son iguales.</p>
<p>Es muy importante tener en cuenta que si algo debe representarse como un objeto de valor o una entidad, depende del contexto en el que se utilice.</p>
<h2 id="atributos-de-los-value-objects">Atributos de los Value Objects:</h2>
<h2 id="inmutabilidad">Inmutabilidad:</h2>
<p>Un objeto no puede ser cambiado por nadie. Una vez creado, solo se puede clonar, por lo que la lógica que creó el objeto confía en que los datos nunca se alterarán. Esto agrega durabilidad adicional al sistema por diseño.</p>
<h2 id="validacion-incorporada">Validación incorporada:</h2>
<p>Un objeto contiene validadores integrados que imponen su formato interno. Digamos, una dirección debe tener una ciudad, un código postal y una dirección postal.</p>
<p>Cada vez que crea una instancia de un nuevo objeto de dirección, debe proporcionarle datos válidos; de lo contrario, la creación de instancia del objeto falla.</p>
<h2 id="ejemplo-de-un-value-object">Ejemplo de un Value Object:</h2>
<pre><code><span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Money</span>
</span>{
    <span class="hljs-comment">/** <span class="hljs-doctag">@var</span> int */</span>
    <span class="hljs-keyword">private</span> $value;

    <span class="hljs-comment">/** <span class="hljs-doctag">@var</span> string */</span>
    <span class="hljs-keyword">private</span> $currency;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
        <span class="hljs-keyword">int</span> $value, 
        <span class="hljs-keyword">string</span> $currency = <span class="hljs-string">'USD'</span>
    </span>)</span>{
        <span class="hljs-keyword">$this</span>-&gt;value = $value;
        <span class="hljs-keyword">$this</span>-&gt;currency = $currency;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">equals</span>(<span class="hljs-params">Money $money</span>): <span class="hljs-title">bool</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;value === $money-&gt;value
            &amp;&amp; <span class="hljs-keyword">$this</span>-&gt;currency === $money-&gt;currency;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getValue</span>(<span class="hljs-params"></span>): <span class="hljs-title">int</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;value;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getCurrency</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;currency;
    }
}
</code></pre><h2 id="ejemplo-de-una-entidad">Ejemplo de una Entidad:</h2>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span>
</span>{
    <span class="hljs-comment">/** <span class="hljs-doctag">@var</span> int */</span>
    <span class="hljs-keyword">private</span> $id;

    <span class="hljs-comment">/** <span class="hljs-doctag">@var</span> string */</span>
    <span class="hljs-keyword">private</span> $name;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $name</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;name = $name;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">equals</span>(<span class="hljs-params">Person $person</span>): <span class="hljs-title">bool</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span> === $person;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getId</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;id;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getName</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;name;
    }
}
</code></pre><p>Por tanto, los value objects son clases que definen tipos de valores que pueden ser utilizados en cualquier parte de nuestro sistema.</p>
<p>Lo interesante de ellos es que encapsulan información valiosa de nuestro core business y por otro lado, que son fácilmente serializables y totalmente desacoplados a cualquier tecnología.</p>
<p>Y por otro lado, como vemos en el ejemplo, las entidades contienen identificadores “ID” que identifican entidades por tanto una entidad nunca sera igual a otra pese a que su contenido relevante sea el mismo.</p>
<h2 id="referencias-sobre-los-value-objects">Referencias sobre los Value Objects</h2>
<ul>
<li><a target="_blank" href="https://martinfowler.com/bliki/ValueObject.html">ValueObject by M.Fowler</a></li>
</ul>
<p>Esto corresponde entonces al principio <strong>Tell Don’t Ask </strong>mostrado en mi <strong>post anterior</strong>.</p>
<p>Recuerda que si tienes alguna sugerencia o pregunta, no dudes en dejar tus comentarios al final del post.</p>
<p>Si te gustó este post, ayúdame a que pueda servirle a muchas más personas, compartiendo mis contenidos en tus redes sociales.</p>
<p>Espero que este post haya sido de gran ayuda para ti, y como siempre, cualquier inquietud o duda que tengas, puedes contactarme por cualquiera de las vías disponibles, o dejando tus comentarios al final de este post. También puedes sugerir que temas o post te gustaría leer a futuro.</p>
]]></content:encoded></item><item><title><![CDATA[Constructores Semánticos / Named Constructors en PHP]]></title><description><![CDATA[Constructores semánticos ó named constructors es un pequeño patrón de refactoring que nos permite eliminar complejidad de los constructores cuando estos implican conocer detalles a fondo de la implementación del mismo.
Tenemos el siguiente ejemplo:
c...]]></description><link>https://franciscougalde.com/constructores-semanticos-named-constructors-en-php</link><guid isPermaLink="true">https://franciscougalde.com/constructores-semanticos-named-constructors-en-php</guid><category><![CDATA[PHP]]></category><category><![CDATA[design patterns]]></category><category><![CDATA[software development]]></category><category><![CDATA[software architecture]]></category><category><![CDATA[clean code]]></category><dc:creator><![CDATA[Francisco Ugalde]]></dc:creator><pubDate>Sun, 28 Jun 2020 13:00:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628695006759/sVVxR0wVi.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Constructores semánticos</strong> ó <strong>named constructors</strong> es un pequeño patrón de refactoring que nos permite eliminar complejidad de los constructores cuando estos implican conocer detalles a fondo de la implementación del mismo.</p>
<p>Tenemos el siguiente ejemplo:</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Price</span>
</span>{
    <span class="hljs-keyword">private</span> $amount;
    <span class="hljs-keyword">private</span> $currency;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params"><span class="hljs-keyword">float</span> $amount, <span class="hljs-keyword">string</span> $currency</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;checkAmount($amount);
        <span class="hljs-keyword">$this</span>-&gt;checkCurrency($currency);
        <span class="hljs-keyword">$this</span>-&gt;amount = $amount;
        <span class="hljs-keyword">$this</span>-&gt;currency = $currency;
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">checkAmount</span>(<span class="hljs-params"><span class="hljs-keyword">float</span> $amount</span>)
    </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-number">0</span> &gt;= $amount) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">RuntimeException</span>();
        }
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">checkCurrency</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $currency</span>)
    </span>{
        $allowedCurrencies = [<span class="hljs-string">'EUR'</span>, <span class="hljs-string">'USD'</span>, <span class="hljs-string">'GBP'</span>];

        <span class="hljs-keyword">if</span> (!in_array($currency, $allowedCurrencies)) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">RuntimeException</span>();
        }
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">amount</span>(<span class="hljs-params"></span>) : <span class="hljs-title">float</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;amount;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">currency</span>(<span class="hljs-params"></span>) : <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;currency;
    }
}
</code></pre><p>En este ejemplo podemos ver rápidamente un pequeño “<a target="_blank" href="https://martinfowler.com/bliki/ValueObject.html"><em>*</em>Value Object</a><em>*</em>” que representaría un precio. El value object se compone de dos atributos, la cantidad y la divisa a usar.</p>
<p>Más adelante en otro post estaré ampliando un poco más sobre lo que son los <strong>value objects</strong> ó <strong>objetos de valor</strong>.</p>
<p>Tal cual está diseñado, este <strong>value object</strong> nos obliga a conocer detalles de su implementación, como por ejemplo qué divisas soparte y cuáles no.</p>
<h2 id="implementacion-de-constructores-semanticos-o-named-constructors">Implementación de Constructores Semánticos ó Named Constructors</h2>
<p>Para aplicar el refactoring de los <strong>constructores semánticos</strong> ó <strong>named constructors </strong>hay que seguir unos pocos pasos:</p>
<ul>
<li><p>Convertir el constructor en privado</p>
</li>
<li><p>Crear uno o varios métodos estáticos que usando el constructor de la forma adecuada, devuelvan un nuevo objeto.</p>
</li>
<li><p>Darle a los nuevos métodos estáticos un nombre que describa su intencionalidad (Aquí entra la parte semántica).</p>
</li>
<li><p>Sustituir las antiguas llamas al constructor por llamadas a los nuevos métodos estáticos</p>
</li>
</ul>
<p>Veamos un ejemplo de este refactor:</p>
<pre><code><span class="hljs-meta">&lt;?php</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Price</span>
</span>{
    <span class="hljs-keyword">private</span> $amount;
    <span class="hljs-keyword">private</span> $currency;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params"><span class="hljs-keyword">float</span> $amount, <span class="hljs-keyword">string</span> $currency</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;checkAmount($amount);
        <span class="hljs-keyword">$this</span>-&gt;checkCurrency($currency);
        <span class="hljs-keyword">$this</span>-&gt;amount = $amount;
        <span class="hljs-keyword">$this</span>-&gt;currency = $currency;
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">checkAmount</span>(<span class="hljs-params"><span class="hljs-keyword">float</span> $amount</span>)
    </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-number">0</span> &gt;= $amount) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">RuntimeException</span>();
        }
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">checkCurrency</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $currency</span>)
    </span>{
        $allowedCurrencies = [<span class="hljs-string">'EUR'</span>, <span class="hljs-string">'USD'</span>, <span class="hljs-string">'GBP'</span>];

        <span class="hljs-keyword">if</span> (!in_array($currency, $allowedCurrencies)) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">RuntimeException</span>();
        }
    }

    <span class="hljs-keyword">public</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createPricePounds</span>(<span class="hljs-params">$amount</span>)
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">self</span>($amount, <span class="hljs-string">'GBP'</span>);
    }

    <span class="hljs-keyword">public</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createPriceInDollars</span>(<span class="hljs-params">$amount</span>)
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">self</span>($amount, <span class="hljs-string">'USD'</span>);
    }

    <span class="hljs-keyword">public</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createPriceInEuros</span>(<span class="hljs-params">$amount</span>)
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">self</span>($amount, <span class="hljs-string">'EUR'</span>);
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">amount</span>(<span class="hljs-params"></span>) : <span class="hljs-title">float</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;amount;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">currency</span>(<span class="hljs-params"></span>) : <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;currency;
    }
}
</code></pre><p>Como se puede observar, hemos definido el constructor como privado y añadido 3 nuevos métodos:</p>
<ul>
<li><p>createPriceInDollars</p>
</li>
<li><p>createPriceInPounds</p>
</li>
<li><p>createPriceInEuros</p>
</li>
</ul>
<p>Y usarlos es tan sencillo como:</p>
<pre><code>$poundsPrice = Price::createPriceInPounds(<span class="hljs-number">22.5</span>);
$dollarsPrice = Price::createPriceInDollars(<span class="hljs-number">22.5</span>);
$eurosPrice = Price::createPriceInEuros(<span class="hljs-number">22.5</span>);
</code></pre><p>Ahora, la interfaz pública del <strong>value object</strong> expone las distintas formas de crear un precio que soporta, con lo que el programador no debe de conocer detalles internos de su implementación.</p>
<h2 id="consideraciones-finales">Consideraciones Finales</h2>
<p>Esto no deja de ser una variante de implementación del <strong>patrón Factory Method</strong>, en la que el método constructor se implementa en la misma clase y por tanto, ha de ser estático.</p>
<p>Hay otro caso de uso en el que los <strong>constructores semánticos ó named constructors</strong> son de utilidad, y es cuando deseamos simular la sobrecarga del constructor como se hace en <strong>JAVA</strong> por ejemplo u otros lenguajes que lo permiten, pero que en <strong>PHP</strong> no esta disponible incluso en la versión 7.3 de PHP.</p>
<p>La solución pasa por crear nuevos constructores semánticos que nos permitan implementar diferentes constructores con diferentes parámetros.</p>
<p>Aprovecho también para mencionar que en la próxima versión de PHP, la versión 7.4 que esté próxima por ser liberada, han incluido los incluidos las <strong>contravariación de argumentos</strong> como algo nativo.</p>
<p>Esto permitiría sobre escribir métodos de una clase, cambiando los tipos de argumentos que recibe, puedes conocer más acerca de esto en <a target="_blank" href="https://www.franciscougalde.com/2019/08/14/conoce-lo-nuevo-de-php-7-4/">**este post</a>**.</p>
<p>Esto último pudiese ser una variante también como algo adicional a los <strong>constructores semánticos</strong> ó <strong>named constructors</strong>.</p>
<p>Recuerda que si tienes alguna sugerencia o pregunta, no dudes en dejar tus comentarios al final del post.</p>
<p>Si te gustó este post, ayúdame a que pueda servirle a muchas más personas, compartiendo mis contenidos en tus redes sociales.</p>
<p>Espero que este post haya sido de gran ayuda para ti, y como siempre, cualquier inquietud o duda que tengas, puedes contactarme por cualquiera de las vías disponibles, o dejando tus comentarios al final de este post. También puedes sugerir que temas o post te gustaría leer a futuro.</p>
]]></content:encoded></item><item><title><![CDATA[Todo lo nuevo de PHP 8]]></title><description><![CDATA[PHP es lenguaje que recientemente ha cumplido 25 años y no se puede negar lo mucho que ha madurado con el tiempo. En este artículo quiero mostrarte todo lo nuevo de PHP 8.
Ya falta muy poco para conocer todo lo nuevo de PHP 8, se espera que sea liber...]]></description><link>https://franciscougalde.com/todo-lo-nuevo-de-php-8</link><guid isPermaLink="true">https://franciscougalde.com/todo-lo-nuevo-de-php-8</guid><category><![CDATA[PHP]]></category><category><![CDATA[software development]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[programming languages]]></category><category><![CDATA[Programming Tips]]></category><dc:creator><![CDATA[Francisco Ugalde]]></dc:creator><pubDate>Sun, 21 Jun 2020 12:26:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628695207237/dDzN8a3j7.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>PHP es lenguaje que recientemente ha cumplido 25 años y no se puede negar lo mucho que ha madurado con el tiempo. En este artículo quiero mostrarte todo lo nuevo de PHP 8.</p>
<p>Ya falta muy poco para conocer todo lo nuevo de <strong>PHP 8,</strong> se espera que sea liberada en <strong>Diciembre de 2020</strong>, es por ello que he querido preparar este artículo en el que resumiré cuales son las mejoras y nuevas características que traerá consigo muy pronto.</p>
<p>Vale la pena destacar, que toda esta información ha sido obtenida durante sus fases de desarrollo por lo que si llega haber un cambio posterior a la publicación de este post, lo estaré actualizando. Te recomiendo estes pendiente de esta entrada por si hay novedades al respecto.</p>
<h2 id="indice-de-todo-lo-nuevo-de-php-8">Indice de todo lo nuevo de PHP 8</h2>
<ul>
<li><p><a class="post-section-overview" href="#9d1a">JIT</a></p>
</li>
<li><p><a class="post-section-overview" href="#bcb2">Mejoras y nuevas características</a></p>
</li>
<li><p><a class="post-section-overview" href="#a687">Nuevas funciones en PHP</a></p>
</li>
</ul>
<h2 id="jit-rfchttpswikiphpnetrfcjit">JIT (<a target="_blank" href="https://wiki.php.net/rfc/jit">RFC</a>)</h2>
<p>JIT, ó <strong>J</strong>ust <strong>I</strong>n <strong>T</strong>ime por sus siglas, es un compilador que promete significantes mejoras de rendimiento, aunque no siempre dentro del contexto de peticiones web.</p>
<p>Con el compilador JIT activado, el código no sería ejecutado por el VM de Zend, sino directamente por el CPU, lo que supondría una mejora notable en la velocidad de cálculo.</p>
<p>Las mejoras que se obtendrían según <strong>Nikita Popov</strong> son:</p>
<ul>
<li><p>Un rendimiento significativamente mejor para el código numérico.</p>
</li>
<li><p>Un rendimiento ligeramente mejor para el código «típico» de una aplicación web PHP.</p>
</li>
<li><p>El potencial para mover más código de C a PHP, porque PHP será ahora suficientemente rápido.»</p>
</li>
</ul>
<h2 id="mejoras-y-nuevas-caracteristicas">Mejoras y nuevas características</h2>
<h2 id="union-types-rfchttpswikiphpnetrfcuniontypesv2">Union Types (<a target="_blank" href="https://wiki.php.net/rfc/union_types_v2">RFC</a>)</h2>
<p>Existen muchos casos en donde es muy útil manejar varios tipos de parámetros utilizando los <strong>union types</strong>. Bien sea en la definición de los parámetros de entrada, como en los parámetros de retorno de una función</p>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">foo</span>(<span class="hljs-params">Foo|Bar $input</span>): <span class="hljs-title">int</span>|<span class="hljs-title">float</span></span>;
</code></pre><p>Nótese también que el tipo <code>void</code> para métodos que no retornan valores, también puede ser parte de los <strong>union types.</strong></p>
<p>Además, las uniones anulables se pueden escribir usando <code>|null</code>, o usando la existente notación <code>?</code>:</p>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">foo</span>(<span class="hljs-params">Foo|<span class="hljs-literal">null</span> $foo</span>): <span class="hljs-title">void</span></span>;

<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bar</span>(<span class="hljs-params">?Bar $bar</span>): <span class="hljs-title">void</span></span>;
</code></pre><h2 id="attributes-rfchttpswikiphpnetrfcattributesv2">Attributes (<a target="_blank" href="https://wiki.php.net/rfc/attributes_v2">RFC</a>)</h2>
<p>Los atributos, o comúnmente conocidos como anotaciones en otros lenguajes, ofrecen una vía para añadir o especificar mediante metadatos, las propiedades de una clase, sus propiedades y funciones, sin necesidad de crear los docblock (Bloques de documentación).</p>
<p>Un ejemplo de cómo lucirán los atributos en una clase:</p>
<pre><code><span class="hljs-keyword">use</span> <span class="hljs-title">App</span>\\<span class="hljs-title">Attributes</span>\\<span class="hljs-title">ExampleAttribute</span>;

&lt;&lt;ExampleAttribute&gt;&gt;
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Foo</span>
</span>{
    &lt;&lt;ExampleAttribute&gt;&gt;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">const</span> FOO = <span class="hljs-string">'foo'</span>;

    &lt;&lt;ExampleAttribute&gt;&gt;
    <span class="hljs-keyword">public</span> $x;

    &lt;&lt;ExampleAttribute&gt;&gt;
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">foo</span>(<span class="hljs-params">&lt;&lt;ExampleAttribute&gt;&gt; $bar</span>) </span>{ }
}

&lt;&lt;Attribute&gt;&gt;
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExampleAttribute</span>
</span>{
    <span class="hljs-keyword">public</span> $value;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">$value</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;value = $value;
    }
}
</code></pre><h2 id="constructor-property-promotion">Constructor property promotion</h2>
<p>Esta nueva característica es una de las que más me gusta. Personalmente utilizo <strong>Value Objects</strong> y <strong>DTO’s</strong> (Data Transfer Objects ó Objetos de Transferencia de Datos) en mis proyectos como parte de los principios de <strong>Domain Driven Design</strong> y esta novedad potencia aún más su uso.</p>
<p>En resumen, “<strong>property promotion</strong>” te permite combinar la definición de propiedades de una clase, la definición del constructor y la asignación de las respectivas variables a cada propiedad, todo en una sola sintaxis en la lista de parámetros del constructor.</p>
<p>Por lo cual, en vez de hacer esto:</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CustomerDTO</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> $name;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> $email;

<span class="hljs-keyword">public</span> DateTimeImmutable $birth_date;

<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
        <span class="hljs-keyword">string</span> $name, 
        <span class="hljs-keyword">string</span> $email, 
        DateTimeImmutable $birth_date
    </span>) </span>{
        <span class="hljs-keyword">$this</span>-&gt;name = $name;
        <span class="hljs-keyword">$this</span>-&gt;email = $email;
        <span class="hljs-keyword">$this</span>-&gt;birth_date = $birth_date;
    }
}
</code></pre><p>Podrás escribirlo de esta forma:</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CustomerDTO</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> $name, 
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> $email, 
        <span class="hljs-keyword">public</span> DateTimeImmutable $birth_date,
    </span>) </span>{}
}
</code></pre><p>Con esta nueva característica, vienen algunas consideraciones importantes:</p>
<h2 id="solo-en-constructores">Solo en constructores</h2>
<p><strong>“Promoted properties</strong>” pueden ser usadas solo en constructores, esto puede que sea obvio para muchos pero nunca esta demás dejarlo en claro.</p>
<h2 id="no-se-permiten-duplicados">No se permiten duplicados</h2>
<p>No tendrás permitido declarar propiedades de una clase y “<strong>promoted properties</strong>” por lo que esto generará un error:</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyClass</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> $a;

<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> $a,
    </span>) </span>{}
}
</code></pre><h2 id="propiedades-no-tipadas-estan-permitidas">Propiedades no tipadas están permitidas</h2>
<p>Esta permitido utilizar propiedades no tipadas, aún cuando es recomendable y buena práctica mantener nuestras propiedades tipadas:</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyDTO</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
        <span class="hljs-keyword">public</span> $untyped,
    </span>) </span>{}
}
</code></pre><h2 id="valores-por-defecto-simples">Valores por defecto simples</h2>
<p><strong>“Promoted properties</strong>” pueden tener valores por defecto, pero expresiones como <code>new …</code> no están permitidas, por lo que el siguiente ejemplo nos arrojaría un error:</p>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> $name = <span class="hljs-string">'Brent'</span>,
    <span class="hljs-keyword">public</span> DateTimeImmutable $date = <span class="hljs-keyword">new</span> DateTimeImmutable(<span class="hljs-params"></span>),
</span>) </span>{}
</code></pre><h2 id="combinar-promoted-properties-y-propiedades-normales">Combinar “promoted properties” y propiedades normales</h2>
<p>No todos los constructores deben usar “promotion properties” por lo que puedes hacer un mix de la siguiente forma.</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyClass</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> $b;

<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> $a,
        <span class="hljs-keyword">string</span> $b,
    </span>) </span>{
        <span class="hljs-keyword">$this</span>-&gt;b = $b;
    }
}
</code></pre><p>Lo que si es que hay que tener cuidado de mezclar estas sintaxis, si notas que el código se torna difícil de leer, lo mejor es utilizar constructores normales en su lugar.</p>
<h2 id="acceso-a-promoted-properties-desde-el-cuerpo-del-constructor">Acceso a “promoted properties” desde el cuerpo del constructor</h2>
<p>Esta permitido leer los “”promoted properties en el cuerpo del constructor, esto es útil si necesitas añadir validación extra. Puedes utilizar ambas, la variable local y la variable de instancia, ambas funcionan bien.</p>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> $a,
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> $b,
</span>) </span>{
    assert(<span class="hljs-keyword">$this</span>-&gt;a &gt;= <span class="hljs-number">100</span>);

<span class="hljs-keyword">if</span> ($b &gt;= <span class="hljs-number">0</span>) {
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">InvalidArgumentException</span>(<span class="hljs-string">'…'</span>);
    }
}
</code></pre><h2 id="comentarios-en-promoted-properties">Comentarios en promoted properties</h2>
<p>Puedes añadir bloques de comentarios en las <strong>promoted</strong> <strong>properties</strong>, las cuales estarán disponibles vía reflection:</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyClass</span> 
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
        <span class="hljs-comment">/** @var string */</span><span class="hljs-keyword">public</span> $a,
    </span>) </span>{}
}

$property = <span class="hljs-keyword">new</span> ReflectionProperty(MyClass::class, <span class="hljs-string">'a'</span>);

$property-&gt;getDocComment(); <span class="hljs-comment">// "/** @var string */"</span>
</code></pre><h2 id="atributos">Atributos</h2>
<p>Tal como los bloques de comentarios, los atributos son permitidos en las <strong>promoted properties</strong>, este ejemplo:</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyClass</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
        &lt;&lt;MyAttribute&gt;&gt;
        <span class="hljs-keyword">public</span> $a,  
    </span>) </span>{}
}
</code></pre><p>Será convertido a:</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyClass</span> 
</span>{
    &lt;&lt;MyAttribute&gt;&gt;
    <span class="hljs-keyword">public</span> $a;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
        &lt;&lt;MyAttribute&gt;&gt;
        $a,
    </span>) </span>{
        <span class="hljs-keyword">$this</span>-&gt;a = $a;
    }
}
</code></pre><h2 id="no-esta-permitido-usarlas-en-constructores-abstractos">No esta permitido usarlas en constructores abstractos</h2>
<p>El siguiente ejemplo nos arrojaría un error:</p>
<pre><code><span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">A</span>
</span>{
    <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> $a,
    </span>) </span>{}
}
</code></pre><h2 id="esta-permitido-en-traits">Esta permitido en Traits</h2>
<p>No solo esta permitido en clases si no que también en Traits:</p>
<pre><code><span class="hljs-keyword">trait</span> MyTrait
{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> $a,
    </span>) </span>{}
}
</code></pre><h2 id="var-no-esta-soportado"><code>var</code> no está soportado</h2>
<p>Solo <code>public</code>, <code>protected</code> y <code>private</code> son las únicas palabras válidas, el siguiente ejemplo nos arrojaría un error:</p>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
    <span class="hljs-keyword">var</span> <span class="hljs-keyword">string</span> $a,
</span>) </span>{}
</code></pre><h2 id="variadic-parameters-no-pueden-ser-promovidos">Variadic parameters no pueden ser promovidos</h2>
<p>El siguiente ejemplo nos arrojará un error:</p>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> ...$a,
</span>) </span>{}
</code></pre><h2 id="reflection-para-ispromoted">Reflection para <code>isPromoted</code></h2>
<p>Ambos, <code>ReflectionProperty</code> y <code>ReflectionParameter</code> poseen un nuevo método <code>isPromoted</code> para verificar si una propiedad o método de una clase es promovida</p>
<h2 id="herencia">Herencia</h2>
<p>Dado que los constructores PHP no necesitan seguir la declaración de su constructor padre, hay poco que decir: se permite la herencia. Sin embargo, si necesita pasar propiedades del constructor secundario al constructor primario, deberá pasarlas manualmente:</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">A</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
        <span class="hljs-keyword">public</span> $a,
    </span>) </span>{}
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">B</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">A</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
        $a,
        <span class="hljs-keyword">public</span> $b,    
    </span>) </span>{
        <span class="hljs-built_in">parent</span>::__construct($a);
    }
}
</code></pre><h2 id="nuevas-funciones-en-php">Nuevas funciones en PHP</h2>
<h2 id="nuevo-tipo-de-retorno-static-rfchttpswikiphpnetrfcthrowexpression">Nuevo tipo de retorno <code>static</code> (<a target="_blank" href="https://wiki.php.net/rfc/throw_expression">RFC</a>)</h2>
<p>Mientras que era posible retornar <code>self</code>, <code>static</code> no era un tipo de retorno válido hasta PHP 8:</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Foo</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">test</span>(<span class="hljs-params"></span>): <span class="hljs-title">static</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">static</span>();
    }
}
</code></pre><h2 id="nuevo-tipo-mixed-rfchttpswikiphpnetrfcmixedtypev2">Nuevo tipo <code>mixed</code> (<a target="_blank" href="https://wiki.php.net/rfc/mixed_type_v2">RFC</a>)</h2>
<p>Algunos podrían creer que es un mal necesario: el tipo “mixto” hace que muchos tengan sentimientos encontrados. Sin embargo, hay un muy buen argumento para hacerlo: un tipo faltante puede significar muchas cosas en PHP:</p>
<ul>
<li><p>Una función no devuelve nada o es nula</p>
</li>
<li><p>Estamos esperando uno de varios tipos</p>
</li>
<li><p>Esperamos un tipo que no pueda ser insinuado en <strong>PHP</strong></p>
</li>
</ul>
<p>Debido a las razones antes mencionadas, es bueno que el tipo <code>mixed</code> sea añadido. <code>mixed</code> en si mismo significa uno de estos tipos:</p>
<ul>
<li><p><code>array</code></p>
</li>
<li><p><code>bool</code></p>
</li>
<li><p><code>callable</code></p>
</li>
<li><p><code>int</code></p>
</li>
<li><p><code>float</code></p>
</li>
<li><p><code>null</code></p>
</li>
<li><p><code>object</code></p>
</li>
<li><p><code>resource</code></p>
</li>
<li><p><code>string</code></p>
</li>
</ul>
<p>Note that <code>mixed</code> can also be used as a parameter or property type, not just as a return type.</p>
<p>Also note that since <code>mixed</code> already includes <code>null</code>, it's not allowed to make it nullable. The following will trigger an error:</p>
<p>Ten en cuenta que <code>mixed</code> también se puede usar como parámetro o tipo de propiedad, no solo como tipo de retorno.</p>
<p>También tenga en cuenta que dado que <code>mixed</code> ya incluye<code>null</code>, no está permitido hacerlo anulable. Lo anterior arrojaría un error como este:</p>
<pre><code>// Fatal error: Mixed <span class="hljs-keyword">types</span> cannot be nullable, <span class="hljs-keyword">null</span> <span class="hljs-keyword">is</span> already part <span class="hljs-keyword">of</span> the mixed <span class="hljs-keyword">type</span>.<span class="hljs-keyword">function</span> bar(): ?mixed {}
</code></pre><h2 id="throw-expression-rfchttpswikiphpnetrfcthrowexpression">Throw expression (<a target="_blank" href="https://wiki.php.net/rfc/throw_expression">RFC</a>)</h2>
<p>Este RFC cambia el <code>throw</code> de ser un statement a ser una expresión, lo cual hace posible arrojar una excepción en multiples lugares:</p>
<pre><code>$triggerError = <span class="hljs-function"><span class="hljs-keyword">fn</span> (<span class="hljs-params"></span>) =&gt; <span class="hljs-title">throw</span> <span class="hljs-title">new</span> <span class="hljs-title">MyError</span>(<span class="hljs-params"></span>)</span>;

$foo = $bar[<span class="hljs-string">'offset'</span>] ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> OffsetDoesNotExist(<span class="hljs-string">'offset'</span>);
</code></pre><h2 id="permitiendo-class-en-objetos-rfchttpswikiphpnetrfcclassnameliteralonobject">Permitiendo <code>::class</code> en objetos (<a target="_blank" href="https://wiki.php.net/rfc/class_name_literal_on_object">RFC</a>)</h2>
<p>Una pequeña pero super útil nueva característica: Ahora es posible usar <code>::class</code> en objetos, en lugar de tener que usar la función <code>get_class()</code> sobre ellos. Esta nueva característica funciona igual a <code>get_class()</code>.</p>
<pre><code>$foo = <span class="hljs-keyword">new</span> Foo();

var_dump($foo::class);
</code></pre><h2 id="catches-sin-captura-rfc">Catches sin captura (RFC)</h2>
<p>Cada vez que se requería capturar una excepción antes de <strong>PHP 8</strong>, se debía almacenar en una variable, independientemente de si usaba esa variable o no. Con Catches sin captura, se puede omitir la variable, por lo que en lugar de esto:</p>
<pre><code><span class="hljs-keyword">try</span> {
    <span class="hljs-comment">// Something goes wrong</span>
} <span class="hljs-keyword">catch</span> (MySpecialException $exception) {
    Log::error(<span class="hljs-string">"Something went wrong"</span>);
}
</code></pre><p>Podremos hacer esto:</p>
<pre><code><span class="hljs-keyword">try</span> {
    <span class="hljs-comment">// Something goes wrong</span>
} <span class="hljs-keyword">catch</span> (MySpecialException) {
    Log::error(<span class="hljs-string">"Something went wrong"</span>);
}
</code></pre><p>Ten en cuenta que es necesario especificar siempre el tipo, no puede tener un <code>catch</code> vacío. Si desea capturar todas las excepciones y errores, puede usar <code>Throwable</code> como tipo de captura.</p>
<h2 id="coma-final-en-listado-de-parametros-rfchttpswikiphpnetrfctrailingcommainparameterlist">Coma final en listado de parámetros (<a target="_blank" href="https://wiki.php.net/rfc/trailing_comma_in_parameter_list">RFC</a>)</h2>
<p>Ya posible cuando se llama a una función, todavía faltaba el soporte de coma final en las listas de parámetros. Ahora está permitido en <strong>PHP 8</strong>, lo que significa que puede hacer lo siguiente:</p>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">
    <span class="hljs-keyword">string</span> $parameterA,
    <span class="hljs-keyword">int</span> $parameterB,
    Foo $objectfoo,
</span>) </span>{
    <span class="hljs-comment">// …</span>
}
</code></pre><p>De cierta forma, esto se asemeja a la definición de arrays en donde sí podemos colocar una coma en el ultimo elemento definido.</p>
<h2 id="crear-objetos-datetime-desde-interfaz">Crear objetos <code>DateTime</code> desde interfaz</h2>
<p>Ya puede crear un objeto <code>DateTime</code> a partir de un objeto <code>DateTimeImmutable</code> utilizando <code>DateTime::createFromImmutable($immutableDateTime)</code>. Al agregar <code>DateTime::createFromInterface()</code> y <code>DatetimeImmutable::createFromInterface()</code> ahora hay una forma generalizada de convertir los objetos <code>DateTime</code> y <code>DateTimeImmutable</code> entre sí.</p>
<pre><code>DateTime::createFromInterface(DateTimeInterface $other);

DateTimeImmutable::createFromInterface(DateTimeInterface $other);
</code></pre><h2 id="nueva-interfaz-stringable-rfchttpswikiphpnetrfcstringable">Nueva interfaz <code>Stringable</code> (<a target="_blank" href="https://wiki.php.net/rfc/stringable">RFC</a>)</h2>
<p>La interfaz <code>Stringable</code> se puede usar para escribir una sugerencia de cualquier cosa que sea una cadena o implemente <code>__toString()</code>. Además, cada vez que una clase implementa <code>__toString()</code>, implementa automáticamente la interfaz detrás de escena y no hay necesidad de implementarla manualmente.</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Foo</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__toString</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">'foo'</span>;
    }
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bar</span>(<span class="hljs-params">Stringable $stringable</span>) </span>{ <span class="hljs-comment">/* … */</span> }

bar(<span class="hljs-keyword">new</span> Foo());
bar(<span class="hljs-string">'abc'</span>);
</code></pre><h2 id="mejoras-de-metodos-abstractos-en-traits-rfchttpswikiphpnetrfcabstracttraitmethodvalidation">Mejoras de métodos abstractos en Traits (<a target="_blank" href="https://wiki.php.net/rfc/abstract_trait_method_validation">RFC</a>)</h2>
<p>Los <strong>Traits</strong> pueden especificar métodos abstractos que deben ser implementados por las clases que los usan. Sin embargo, hay una advertencia: antes de <strong>PHP</strong> <strong>8</strong>, la firma de estas implementaciones de métodos no estaba validada. El siguiente ejemplo era válido:</p>
<pre><code><span class="hljs-keyword">trait</span> Test {
    <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">test</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> $input</span>): <span class="hljs-title">int</span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UsesTrait</span>
</span>{
    <span class="hljs-keyword">use</span> <span class="hljs-title">Test</span>;

<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">test</span>(<span class="hljs-params">$input</span>)
    </span>{
        <span class="hljs-keyword">return</span> $input;
    }
}
</code></pre><p><strong>PHP 8</strong> realizará la validación adecuada de la firma del método cuando use un <strong>Trait</strong> e implemente sus métodos abstractos. Esto significa que deberás escribir esto en su lugar:</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UsesTrait</span>
</span>{
    <span class="hljs-keyword">use</span> <span class="hljs-title">Test</span>;

<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">test</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> $input</span>): <span class="hljs-title">int</span>
    </span>{
        <span class="hljs-keyword">return</span> $input;
    }
}
</code></pre><h2 id="implementacion-de-objeto-tokengetall-rfchttpswikiphpnetrfctokenasobject">Implementación de Objeto <code>token_get_all()</code> (<a target="_blank" href="https://wiki.php.net/rfc/token_as_object">RFC</a>)</h2>
<p>La función <code>token_get_all()</code> devuelve un array de valores. Este RFC agrega una clase <code>PhpToken</code> con un método <code>PhpToken::getAll().</code> Esta implementación funciona con objetos en lugar de valores simples. Consume menos memoria y es más fácil de leer.</p>
<h2 id="ext-json-siempre-disponible-rfchttpswikiphpnetrfcalwaysenablejson"><code>ext-json</code> siempre disponible (<a target="_blank" href="https://wiki.php.net/rfc/always_enable_json">RFC</a>)</h2>
<p>Anteriormente era posible compilar PHP sin la extensión JSON activa, esto ya no es posible nunca más. Desde que JSON es usado tan ampliamente, es mejor que los desarrolladores puedan siempre confiar en que este siempre allí, en vez de tener que asegurarse primero de que la extensión exista.</p>
<h2 id="nuevas-funciones-en-php">Nuevas funciones en PHP</h2>
<h2 id="funcion-strcontains-rfchttpswikiphpnetrfcstrcontains">Función <code>str_contains()</code> (<a target="_blank" href="https://wiki.php.net/rfc/str_contains">RFC</a>)</h2>
<p>Algunos podrían decir que esto era posible desde hace mucho tiempo, pero finalmente ya no tenemos que depender de <code>strpos</code> para saber si una cadena contiene otra cadena.</p>
<p>En lugar de hacer esto:</p>
<pre><code><span class="hljs-keyword">if</span> (strpos(<span class="hljs-string">'string with lots of words'</span>, <span class="hljs-string">'words'</span>) !== <span class="hljs-keyword">false</span>) { 
    <span class="hljs-comment">/* … */</span> 
}
</code></pre><p>Podremos hacer esto:</p>
<pre><code><span class="hljs-selector-tag">if</span> (str_contains(<span class="hljs-string">'string with lots of words'</span>, <span class="hljs-string">'words'</span>)) { 
    <span class="hljs-comment">/* … */</span> 
}
</code></pre><p>Parece algo tonto o sencillo, pero cosas como estas hacen falta en todos los lenguajes, son como especies de helpers que simplifican y optimizan el proceso de desarrollo.</p>
<h2 id="funciones-strstartswith-y-strendswith-rfchttpswikiphpnetrfcaddstrstartswithandendswithfunctions">Funciones <code>str_starts_with()</code> y <code>str_ends_with()</code> (<a target="_blank" href="https://wiki.php.net/rfc/add_str_starts_with_and_ends_with_functions">RFC</a>)</h2>
<p>Estas dos maravillosas funciones han sido añadidas al core de PHP. Un ejemplo vale más que 1000 palabras para describir lo que hacen:</p>
<pre><code><span class="hljs-selector-tag">str_starts_with</span>(<span class="hljs-string">'haystack'</span>, <span class="hljs-string">'hay'</span>); <span class="hljs-comment">// true</span>
<span class="hljs-selector-tag">str_ends_with</span>(<span class="hljs-string">'haystack'</span>, <span class="hljs-string">'stack'</span>); <span class="hljs-comment">// true</span>
</code></pre><h2 id="funcion-fdiv">Función <code>fdiv()</code></h2>
<p>La nueva función <code>fdiv()</code> realiza algo similar a las funciones <code>fmod()</code> y <code>intdiv()</code>, lo cual permite la división por 0. En lugar de errores obtendremos <code>INF</code>, <code>-INF</code> ó <code>NAN</code>, dependiendo del caso.</p>
<h2 id="funcion-getdebugtyperfchttpswikiphpnetrfcgetdebugtype">Función <code>get_debug_type()</code>(<a target="_blank" href="https://wiki.php.net/rfc/get_debug_type">RFC</a>)</h2>
<p><code>get_debug_type()</code> retorna el tipo de una variable. Suena como algo que ya <code>gettype()</code> hace?,<code>get_debug_type()</code> retorna un output para arrays, strings, clases anónimas y objetos, mas útil.</p>
<p>For ejemplo, invocar <code>gettype()</code> en la clase <code>\\Foo\\Bar</code> podría retornar <code>object</code>. Usar <code>get_debug_type()</code> retornará el class name.</p>
<h2 id="funcion-getresourceid">Función <code>get_resource_id()</code></h2>
<p>Los recursos son variables especiales en PHP, que se refieren a recursos externos. Un ejemplo es una conexión MySQL, otro un identificador de archivo.</p>
<p>A cada uno de esos recursos se le asigna una ID, aunque anteriormente la única forma de saber esa identificación era enviar el recurso a <code>int</code>:</p>
<pre><code>$resourceId = (<span class="hljs-keyword">int</span>) $resource;
</code></pre><p><strong>PHP 8</strong> añade la función <code>get_resource_id()</code>, haciendo esta operación más obvia y type-safe:</p>
<pre><code>$resourceId = get_resource_id($resource);
</code></pre><p>Es todo por ahora, recuerda estar pendiente de este post, ya que si aparecen nuevas características, trataré de actualizar el post con lo nuevo.</p>
<p>Recuerda que si tienes alguna sugerencia o pregunta, no dudes en dejar tus comentarios al final del post.</p>
<p>Si te gustó este post, ayúdame a que pueda servirle a muchas más personas, compartiendo mis contenidos en tus redes sociales.</p>
<p>Espero que este post haya sido de gran ayuda para ti, y como siempre, cualquier inquietud o duda que tengas, puedes contactarme por cualquiera de las vías disponibles, o dejando tus comentarios al final de este post. También puedes sugerir que temas o post te gustaría leer a futuro.</p>
]]></content:encoded></item><item><title><![CDATA[Extract Params Into Class: Refactoring en PHP]]></title><description><![CDATA[“Extract Params Into Class” como su nombre lo sugiere, es un patrón de refactoring muy común el cual sugiere extraer los parámetros de una función y añadirlos dentro de una clase mediante sus propiedades.
Veamos un simple ejemplo:
Lo habitual al crea...]]></description><link>https://franciscougalde.com/extract-params-into-class-refactoring-en-php</link><guid isPermaLink="true">https://franciscougalde.com/extract-params-into-class-refactoring-en-php</guid><category><![CDATA[PHP]]></category><category><![CDATA[software architecture]]></category><category><![CDATA[clean code]]></category><category><![CDATA[software development]]></category><category><![CDATA[refactoring]]></category><dc:creator><![CDATA[Francisco Ugalde]]></dc:creator><pubDate>Wed, 17 Jun 2020 17:58:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628695617008/-nGQBIAcJ.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>“Extract Params Into Class</em>” como su nombre lo sugiere, es un patrón de refactoring muy común el cual sugiere extraer los parámetros de una función y añadirlos dentro de una clase mediante sus propiedades.</p>
<p>Veamos un simple ejemplo:</p>
<h2 id="lo-habitual-al-crear-una-funcion">Lo habitual al crear una función</h2>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RegisterUser</span>(<span class="hljs-params">
    <span class="hljs-keyword">string</span> $name,
    <span class="hljs-keyword">string</span> $lastName,
    <span class="hljs-keyword">string</span> $email,
    <span class="hljs-keyword">string</span> $streetAddress,
    <span class="hljs-keyword">int</span> $streetNumber,
    <span class="hljs-keyword">string</span> $state,
    <span class="hljs-keyword">string</span> $country,
    <span class="hljs-keyword">int</span> $zipCode
</span>) </span>{
    <span class="hljs-comment">// ...</span>
    <span class="hljs-comment">// Here comes the implementation </span>
}
</code></pre><h2 id="refactorizando-usando-extract-params-into-class">Refactorizando usando Extract Params Into Class</h2>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RegisterUser</span>(<span class="hljs-params">
    User $user,
    Address $address
</span>) </span>{
    <span class="hljs-comment">// ...</span>
    <span class="hljs-comment">// Here comes the implementation</span>
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span>
</span>{
    <span class="hljs-keyword">private</span> $name;
    <span class="hljs-keyword">private</span> $lastName;
    <span class="hljs-keyword">private</span> $email;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span>  <span class="hljs-title">__constructor</span>(<span class="hljs-params">
        <span class="hljs-keyword">string</span> $name,
        <span class="hljs-keyword">string</span> $lastName,
        <span class="hljs-keyword">string</span> $email
    </span>) </span>{
        <span class="hljs-keyword">$this</span>-&gt;name = $name;
        <span class="hljs-keyword">$this</span>-&gt;lastName = $lastName;
        <span class="hljs-keyword">$this</span>-&gt;email = $email;
    }

    <span class="hljs-comment">// ... semantic getters</span>
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Address</span>
</span>{
    <span class="hljs-keyword">private</span> $streetAddress;
    <span class="hljs-keyword">private</span> $streetNumber;
    <span class="hljs-keyword">private</span> $state;
    <span class="hljs-keyword">private</span> $country;
    <span class="hljs-keyword">private</span> $zipCode;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span>  <span class="hljs-title">__constructor</span>(<span class="hljs-params">
        <span class="hljs-keyword">string</span> $streetAddress,
        <span class="hljs-keyword">int</span> $streetNumber,
        <span class="hljs-keyword">string</span> $state,
        <span class="hljs-keyword">string</span> $country,
        <span class="hljs-keyword">int</span> $zipCode
    </span>) </span>{
        <span class="hljs-keyword">$this</span>-&gt;streetAddress = $streetAddress;
        <span class="hljs-keyword">$this</span>-&gt;streetNumber = $streetNumber;
        <span class="hljs-keyword">$this</span>-&gt;state = $state;
        <span class="hljs-keyword">$this</span>-&gt;country = $country;
        <span class="hljs-keyword">$this</span>-&gt;zipCode = $zipCode;
    }

    <span class="hljs-comment">// ... semantic getters</span>
}
</code></pre><h2 id="consideraciones-finales">Consideraciones Finales</h2>
<p>Particularmente, es uno de los patrones que uso cuando de refactoring se trata siempre que me encuentro frente una aplicación que fue implementada por alguien más.</p>
<p>O porque en muchos casos, cuando estamos implementando un requerimiento, vamos dejando un esqueleto previo donde debe ir cada cosa, sobre todo cuando se trata de cosas complejas.</p>
<p>Pero que al final, al tener una vista general de donde debe ir cada cosa, siempre encontramos una mejor forma de refactorizar y aquí es donde entra este patrón el cual nos puede ser de muchísima ayuda.</p>
<p>Es por esto que con el uso del patrón de refactoring “<strong><em>Extract Params Into Class</em></strong>” estaremos ante una implementación más limpia, aprovechando siempre la programación orientada a objetos.</p>
<p>A su vez, estaríamos contribuyendo hacia el uso de los principios de un código limpio (<strong>Clean</strong> <strong>Code</strong>), legible, fácil de entender y por supuesto siguiendo una arquitectura limpia (<strong>Clean</strong> <strong>Architecture</strong>).</p>
<p>Así que no me queda más que recomendarte que lo pongas en práctica en cada uno de tus desarrollos y verás como poco a poco iras añadiendo mas skills a tu carrera profesional.</p>
<p>Recuerda que si tienes alguna sugerencia o pregunta, no dudes en dejar tus comentarios al final del post.</p>
<p>Si te gustó este post, ayúdame a que pueda servirle a muchas más personas, compartiendo mis contenidos en tus redes sociales.</p>
<p>Espero que este post haya sido de gran ayuda para ti, y como siempre, cualquier inquietud o duda que tengas, puedes contactarme por cualquiera de las vías disponibles, o dejando tus comentarios al final de este post. También puedes sugerir que temas o post te gustaría leer a futuro.</p>
]]></content:encoded></item><item><title><![CDATA[Command Pattern en PHP]]></title><description><![CDATA[El patrón Comando ó Command Pattern es un patrón de comportamiento muy común a tener en cuenta en nuestros desarrollos.
El principio de este patrón es convertir operaciones o requests en objetos.

Encapsular una petición como un objeto, de modo que p...]]></description><link>https://franciscougalde.com/command-pattern-en-php</link><guid isPermaLink="true">https://franciscougalde.com/command-pattern-en-php</guid><category><![CDATA[PHP]]></category><category><![CDATA[design patterns]]></category><category><![CDATA[clean code]]></category><category><![CDATA[software development]]></category><category><![CDATA[software architecture]]></category><dc:creator><![CDATA[Francisco Ugalde]]></dc:creator><pubDate>Fri, 12 Jun 2020 16:55:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628695814853/MpEMXzGfm.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>El patrón <strong>Comando</strong> ó <strong>Command Pattern</strong> es un patrón de comportamiento muy común a tener en cuenta en nuestros desarrollos.</p>
<p>El principio de este patrón es convertir operaciones o requests en objetos.</p>
<blockquote>
<p><em>Encapsular una petición como un objeto, de modo que puedan parametrizarse otros objetos con distintas peticiones o colas de peticiones.</em>
<strong>*Command</strong> <strong>Pattern*</strong></p>
</blockquote>
<p>La idea se basa en la necesidad de ejecutar una acción, para la cual creamos un objeto el cual es denominado Command con la información requerida (Propiedades) para ser luego procesada por un handler.</p>
<p>Cada comando al ser despachado, tendrá su propio handler el cual sabra que acción debe realizar con los datos recibidos por el comando.</p>
<p>Los actores que están involucrados en este patrón son:</p>
<ul>
<li><p><strong>Cliente/Invoker</strong>: Es quien inicia la acción a ejecutar, puede ser un controlador o comando de shell.</p>
</li>
<li><p><strong>Command</strong>: Es la clase que encapsula todos los datos requeridos para la ejecución de la acción. Los Command actúan como simples <strong>DTO’s</strong> por lo que son clases que tienen que ser fácilmente serializables.</p>
</li>
<li><p><strong>CommandHandler/Handler</strong>: Es la clase que es invocada en función del comando despachado y la cual contiene toda la lógica de la acción a realizar.</p>
</li>
</ul>
<p>Por convención, todos los <strong><em>handlers</em></strong> deben tener un método en común para ejecutar los comandos. Este método puede llamarse “<strong><em>handle</em></strong>” ó “<strong><em>execute</em></strong>”, o simplemente podemos aprovechar el método mágico de php y llamar al método <strong>__invoke*</strong>.*</p>
<p>Adicionalmente, los comandos deberían implementar una misma interfaz <strong><em>Command</em></strong> y todos los handlers una interfaz <strong><em>CommandHandler</em></strong> con un método <strong>handle</strong>, <strong>execute</strong> o <strong>__invoke</strong> por ejemplo.</p>
<p>De esta manera podemos aprovechar el type hinting para que cada <strong><em>handler</em></strong> sepa a qué comando le corresponde atender.</p>
<p>Por razones de comodidad y estandarización, yo particularmente prefiero utilizar el método mágico <strong>__invoke</strong> de php para los <strong><em>handlers</em></strong> pero es cuestión de cada quien cómo más cómodo con la implementación se sienta.</p>
<p>Pero realmente lo recomiendo usar puesto que se ha convertido en una buena práctica de implementación para este patrón de diseño.</p>
<blockquote>
<p><em>Puedes leer un poco más sobre el [**</em>método mágico de php __invoker](http://php.net/manual/es/language.oop5.magic.php#object.invoke)<strong>
*</strong>Lectura recomendada<em>*</em></p>
</blockquote>
<h2 id="ejemplo-de-implementacion">Ejemplo de implementación</h2>
<pre><code><span class="hljs-keyword">namespace</span> <span class="hljs-title">Application</span>\<span class="hljs-title">Command</span>\<span class="hljs-title">User</span>;

<span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RegisterUserCommand</span>
</span>{
    <span class="hljs-keyword">private</span> $name
    <span class="hljs-keyword">private</span> $email;
    <span class="hljs-keyword">private</span> $password;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>
    (<span class="hljs-params">
        <span class="hljs-keyword">string</span> $name, 
        <span class="hljs-keyword">string</span> $email, 
        <span class="hljs-keyword">string</span> $password
    </span>)</span>{
        <span class="hljs-keyword">$this</span>-&gt;name = $name;
        <span class="hljs-keyword">$this</span>-&gt;email = $email;
        <span class="hljs-keyword">$this</span>-&gt;password = $password;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">name</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;name;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">email</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;email;   
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">password</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;password;   
    }
}

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Application</span>\<span class="hljs-title">CommandHandler</span>;

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">CommandHandlerInterface</span> 
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__invoke</span>(<span class="hljs-params"></span>)</span>;
}

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Application</span>\<span class="hljs-title">CommandHandler</span>\<span class="hljs-title">User</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">Application</span>\<span class="hljs-title">Command</span>\<span class="hljs-title">User</span>\<span class="hljs-title">RegisterUserCommand</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Application</span>\<span class="hljs-title">CommandHandler</span>\<span class="hljs-title">CommandHandlerInterface</span>
<span class="hljs-title">use</span> <span class="hljs-title">Application</span>\<span class="hljs-title">Domain</span>\<span class="hljs-title">Repository</span>\<span class="hljs-title">UserRepository</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Application</span>\<span class="hljs-title">Entity</span>\<span class="hljs-title">User</span>;

<span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RegisterUserHandler</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">CommandHandlerInterface</span>
</span>{
    <span class="hljs-keyword">const</span> MINIMUM_LENGHT = <span class="hljs-number">15</span>;

    <span class="hljs-keyword">private</span> $repository;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span> (<span class="hljs-params">UserRepository $repository</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;repository = $repository;   
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__invoke</span>(<span class="hljs-params">RegisterUserCommand $command</span>)
    </span>{
        $name = $command-&gt;name();
        $email = $command-&gt;email();
        $password = $command-&gt;password();

        <span class="hljs-keyword">$this</span>-&gt;checkEmail();
        <span class="hljs-keyword">$this</span>-&gt;checkPassword();

        $user = <span class="hljs-keyword">new</span> User($name, $email, $password);
        <span class="hljs-keyword">$this</span>-&gt;repository-&gt;save($user);
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">checkEmail</span>(<span class="hljs-params">$email</span>)
    </span>{
        <span class="hljs-keyword">if</span> (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> \<span class="hljs-built_in">Exception</span>(<span class="hljs-string">'Invalid email'</span>);
        }

        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">$this</span>-&gt;repository-&gt;userExists($email)) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> \<span class="hljs-built_in">Exception</span>(<span class="hljs-string">'User already exist'</span>);
        }
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">checkPassword</span>(<span class="hljs-params">$password</span>)
    </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">self</span>::MINIMUM_LENGHT &gt; strlen($password)) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> \<span class="hljs-built_in">Exception</span>(<span class="hljs-string">'Password too short'</span>);
        }
    }
}

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Application</span>\<span class="hljs-title">Controller</span>\<span class="hljs-title">User</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">Application</span>\<span class="hljs-title">Command</span>\<span class="hljs-title">User</span>\<span class="hljs-title">RegisterUserCommand</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Application</span>\<span class="hljs-title">CommandHandler</span>\<span class="hljs-title">User</span>\<span class="hljs-title">RegisterUserHandler</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">HttpFoundation</span>\<span class="hljs-title">JsonResponse</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">HttpFoundation</span>\<span class="hljs-title">Request</span>;

<span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserController</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">registerUser</span>(<span class="hljs-params">Request $request</span>): <span class="hljs-title">Response</span>
    </span>{
        $name = $request-&gt;request-&gt;get(<span class="hljs-string">'name'</span>);
        $email = $request-&gt;request-&gt;get(<span class="hljs-string">'email'</span>);
        $password = $request-&gt;request-&gt;get(<span class="hljs-string">'password'</span>);

        $command = <span class="hljs-keyword">new</span> RegisterUserCommand($name, $email, $password);

        $userRepository = <span class="hljs-keyword">$this</span>-&gt;get(<span class="hljs-string">'redis.user.respository'</span>);
        $handler = <span class="hljs-keyword">new</span> RegisterUserHandler($userRepository);

        <span class="hljs-keyword">try</span> {
            $handler($command);
        } <span class="hljs-keyword">catch</span> (\<span class="hljs-built_in">Exception</span> $e) {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Response($e-&gt;getMessage(), Response::HTTP_BAD_REQUEST);
        }

        <span class="hljs-keyword">return</span> JsonResponse::create(<span class="hljs-string">''</span>, Response::HTTP_CREATED);
    }
}
</code></pre><h2 id="casos-de-uso">Casos de uso</h2>
<ul>
<li><p>En la arquitectura <a target="_blank" href="https://martinfowler.com/bliki/CQRS.html"><em>*</em>CQRS</a><em>*</em>, se maneja la separación de 2 contextos principales, contextos de lectura y contextos de escritura. Por ende se utiliza este patrón para definir comandos para lectura de datos y comandos para escritura de datos los cuales hacen uso de buses para que de cierta forma podamos ejecutarlos de forma síncrona o asíncrona según se requiera para nuestro caso de uso.</p>
</li>
<li><p>Las librerías de <strong>CommandBus</strong> mas conocidas como <strong>Tactician</strong> o <strong>Broadway</strong> hacen uso de este patrón.</p>
</li>
</ul>
<h2 id="conclusion">Conclusión</h2>
<p>Particularmente puedo decirte que este patrón es muy potente y que viene a resolver muchísimas situaciones que de otro modo quizás se complicaría y terminaríamos haciendo un código spaguetti.</p>
<p>En sí este patrón es muy limpio y 100% testable, su implementación es prácticamente fácil y sencilla y en combinación con el uso de un CommandBus como el de la librería <strong>Tactician</strong> o <strong>Broadway</strong> harán de este patrón tu mejor aliado</p>
<p>El patrón Command es una herramienta muy potente, que nos permite crear código muy limpio y testable, su implementación básica es muy sencilla, y el hacer uso de un CommandBus como Tactician es muy sencillo también.</p>
<p>En lo personal lo utilizo muchísimo sobre todo con la arquitectura <strong>CQRS</strong>. He experimentado como utilizar el <a target="_blank" href="https://www.franciscougalde.com/2019/07/17/symfony-como-usar-el-componente-messenger-parte-1/">**componente Messenger de Symfony</a>** para tratar de reemplazar las librerías mencionadas y la verdad es que va muy bien.</p>
<p>He logrado implementar el componente para hacer uso de su <strong>CommandBus</strong> e incluso de sus Transports para encolar los comandos con <strong>RabbitMQ</strong>. Todo sin acoplarme al framework y mantener los principios de la <strong>arquitectura hexagonal</strong> intactos.</p>
<p>Hasta aquí dejaré este post sobre este maravilloso patrón de diseño.</p>
<p>Recuerda que si tienes alguna sugerencia o pregunta, no dudes en dejar tus comentarios al final del post.</p>
<p>Si te gustó este post, ayúdame a que pueda servirle a muchas más personas, compartiendo mis contenidos en tus redes sociales.</p>
<p>Espero que este post haya sido de gran ayuda para ti, y como siempre, cualquier inquietud o duda que tengas, puedes contactarme por cualquiera de las vías disponibles, o dejando tus comentarios al final de este post. También puedes sugerir que temas o post te gustaría leer a futuro.</p>
]]></content:encoded></item><item><title><![CDATA[Desplegar contenedores de Docker en Clouding.io]]></title><description><![CDATA[En este post quiero mostrarte como desplegar contenedores de Docker en **Clouding.io. Para esto, quiero mostrarte como llevar a producción una aplicación de ejemplo con Symfony 4 y Redis**.
La aplicación es solo de ejemplo y se trata de un API Rest s...]]></description><link>https://franciscougalde.com/desplegar-contenedores-de-docker-en-clouding-io</link><guid isPermaLink="true">https://franciscougalde.com/desplegar-contenedores-de-docker-en-clouding-io</guid><category><![CDATA[Cloud]]></category><category><![CDATA[Cloud Computing]]></category><category><![CDATA[deployment]]></category><category><![CDATA[ci-cd]]></category><category><![CDATA[Devops]]></category><dc:creator><![CDATA[Francisco Ugalde]]></dc:creator><pubDate>Mon, 28 Oct 2019 12:13:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628696782237/mNc5LKSJb.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>En este post quiero mostrarte como desplegar contenedores de Docker en <a target="_blank" href="https://clouding.io/">**Clouding.io</a><strong>. Para esto, quiero mostrarte como llevar a producción una aplicación de ejemplo con </strong>Symfony<strong> </strong>4<strong> y </strong>Redis**.</p>
<p>La aplicación es solo de ejemplo y se trata de un <strong>API Rest</strong> sencillo el cual nos permitirá mostrar cómo desplegar nuestra aplicación en dos instancias de .</p>
<h2 id="que-es-cloudingio">¿Qué es Clouding.io?</h2>
<p><strong>Clouding.io</strong> es una empresa española que nos provee de una excelente plataforma de servicios de infraestructura para nuestras aplicaciones, lo que se traduce en: un proveedor de servicios en la nube que nos permite disponer de <strong>Cloud Servers</strong> ó los comúnmente llamados: <strong>VPS</strong> (Servidores privados virtuales).</p>
<h2 id="que-me-gusta-de-cloudingio">¿Qué me gusta de Clouding.io?</h2>
<ul>
<li><p>Sus instancias son totalmente configurables en base a las necesidades de tu aplicación</p>
</li>
<li><p>Nos permite crecer y escalar fácilmente en el tiempo.</p>
</li>
<li><p>Su interfaz de configuración es super minimalista y sencilla, lo cual nos permite intuitivamente aprender a usarla rápidamente.</p>
</li>
<li><p>El rendimiento de sus instancias es increíble.</p>
</li>
<li><p>Me proveen de un servidor de nombres (DNS) gratuito. Por ende podrás gestionar tu dominio para que apunte a tus instancias fácilmente.</p>
</li>
</ul>
<h2 id="desplegar-contenedores-de-docker-en-cloudingio-api-rest-con-symfony-4-y-redis">Desplegar contenedores de Docker en Clouding.io: API Rest con Symfony 4 y Redis</h2>
<p>Para mostrar un poco el ecosistema entre una infraestructura con <strong>Clouding.io</strong> y nuestro software, tomaremos los siguientes requerimientos para demostrar un poco la interacción entre estos aspectos:</p>
<ol>
<li><p>Dispondremos de un endpoint <strong>GET</strong> para obtener un listado de productos el cual:</p>
</li>
<li><p>Si no esta cacheado en <strong>REDIS</strong>, los datos se obtendrán desde <strong>MYSQL</strong>.</p>
</li>
<li><p>Si los datos estan cacheados, se tomarán de <strong>REDIS</strong>.</p>
</li>
<li><p>Dispondremos de un endpoint <strong>POST</strong> para añadir un nuevo producto.</p>
</li>
<li><p>Dispondremos de un endpoint <strong>POST</strong> para invalidar la cache de <strong>Redis</strong> y poder ver el funcionamiento entre <strong>MYSQL</strong> Y <strong>Redis</strong> de una forma clara.</p>
<blockquote>
<p><em>El <strong>API Rest</strong> que usaré es a modo de ejemplo por lo que no incorpora ninguna seguridad mediante token (JWT ó OAuth2) para cada petición. Y por tanto se omiten también muchos de los requerimientos y buenas prácticas sugeridas.</em>
<em>Acotación</em></p>
</blockquote>
</li>
</ol>
<p>En cuanto a la infraestructura que usaremos utilizando <strong>Clouding.io</strong> sera:</p>
<ul>
<li><p>Una instancia (servidor) en donde desplegaremos 2 contenedores, un contenedor para <strong>PHP-FPM</strong>, otro para <strong>NGINX</strong>.</p>
</li>
<li><p>Una instancia (servidor) en donde desplegaremos 2 contenedores. Uno para <strong>MySQL</strong> y otro para <strong>Redis</strong>.</p>
</li>
</ul>
<p>Ahora sí, manos a la obra y pongámonos a <strong>Desplegar contenedores de Docker en Clouding.io.</strong></p>
<blockquote>
<p><em>A partir de aquí, es necesario tener una cuenta en <strong>Clouding.io</strong> activada y con saldo suficiente para poder crear las instancias necesarias.</em>
<em>Consideraciones iniciales</em></p>
</blockquote>
<p>Lo primero que debemos hacer es crear la instancia en donde albergaremos el contenedor de nginx y el contenedor del API Rest en Symfony 4.</p>
<p>Para ello, vamos a acceder a nuestro panel de <strong>Clouding.io</strong> a la sección de “ <strong>Servidores</strong> “:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628329097445/ghy_gaG9m.png" alt /></p>
<p>Hacemos click en el botón “ <strong>Haz click aquí para crear tu primer servidor</strong> “:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628329098877/_za1VYo3r.png" alt /></p>
<p>En la sección “ <strong>Seleccione un Nombre</strong>” le asignaremos el nombre a la instancia, en mi caso le pondré: <strong>API Rest Symfony 4</strong></p>
<p>Si navegamos un poco más abajo, podremos elegir las especificaciones que tendrá nuestra instancia, para este ejemplo, usaré una instancia con las mínimas características posibles. Sólo aumentaré el tamaño del disco a 10GB de espacio.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628329100442/E1itQSccs.png" alt /></p>
<blockquote>
<p><em>Por ahora, no podemos activar la opción de red privada, pero una vez configuremos la segunda instancia, podremos hacerlo para poder comunicarnos entre ambas instancias.</em>
<em>Activar Red Privada</em></p>
</blockquote>
<p>Le damos al botón enviar y con esto se creará nuestra primera instancia de servidor.</p>
<p>Una vez terminado todo el proceso veremos nuestra instancia en la lista de servidores en donde podremos posteriormente ver información pertinente, asi como también podremos escalar ( <strong>redimensionar</strong>) las características de nuestra instancia en caso de ser necesario y a demás realizar una que otra configuración pertinente.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628329101930/y2zHeK1bs.png" alt /></p>
<p>Podremos también apagar o reiniciar nuestra instancia en caso de que sea necesario.</p>
<p>Si hacemos click en el nombre de nuestro servidor, podremos acceder entonces a información importante, así como también podremos configurar mas a fondo nuestra instancia.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628329103430/Vkj4p96kD.png" alt /></p>
<p>Como podemos observar, nos muestra detalles como la IP Pública de nuestra instancia, el nombre de HOST asignado, podrémos descargar nuestras llaves SSH para acceder a nuestra instancia remotamente por la terminal, entre otras cosas más com cambiar la contraseña del usuario root.</p>
<p>Tendremos también acceso a configuración de RED en el respectivo tab situado en la parte superior:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628329105116/hnwcU-Anx.png" alt /></p>
<p>Aquí es donde más adelante debemos configurar la red privada para permitir la comunicación entre los distintos contenedores de cada instancia de servidor.</p>
<p>Adicionalmente, podremos indicar cuales puertos y protocolos estarán abiertos públicamente para su acceso desde el exterior.</p>
<p>Una vez hecho esto, nuestra lista de servidores quedará de la siguiente forma:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628329106600/NnuINJ5J5.png" alt /></p>
<h2 id="configuracion-instancia-para-el-api-rest-en-symfony-4">Configuración instancia para el API Rest en Symfony 4</h2>
<p>Lo siguiente que haremos será configurar nuestros contenedores en la instancia creada para ello. Lo siguiente que haremos es hacer click sobre el nombre de la instancia “ <strong>Api Rest Symfony 4</strong> “ en la lista de servidores.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628329108020/LAaoMxJrx.png" alt /></p>
<p>Una vez allí, podremos obtener los datos para conectarnos vía SSH a la instancia del servidor:</p>
<blockquote>
<p><em>Necesitaremos la IP pública, el usuario para linux y la contraseña (Debemos darle click al icono de “ <strong>ojo</strong> “ para ver la clave asignada). La clave puede ser cambiada por la que queramos.</em>
<em>Acotación</em></p>
</blockquote>
<p>Para conectarnos a la instancia basta con ejecutar el siguiente comando:</p>
<pre><code><span class="hljs-attribute">ssh</span> root@<span class="hljs-number">185.166.215.90</span>
</code></pre><p>Una vez ingresemos el comando, nos solicitará la contraseña de acceso.</p>
<p>Una vez conectados a la instancia, lo primero que haremos será crear el directorio en donde vamos a deplegar el código del <strong>API Rest en Symfony 4</strong>.</p>
<p>En mi caso desplegaré el código en <code>/var/www/html/clouding.io</code></p>
<pre><code>mkdir -p /<span class="hljs-keyword">var</span>/www/html
</code></pre><p>Nos situamos en el directorio:</p>
<pre><code>cd /<span class="hljs-keyword">var</span>/www/html
</code></pre><h2 id="paso-1-clonamos-el-repositorio-del-api-rest">Paso 1: Clonamos el Repositorio del API Rest</h2>
<p>Ahora clonemos el repositorio del <strong>API Rest</strong>:</p>
<pre><code>git <span class="hljs-keyword">clone</span> https:<span class="hljs-comment">//github.com/franciscougalde-com/sf4-mysql-redis-example.git clouding.io</span>
</code></pre><p>Nos situamos en el directorio:</p>
<pre><code><span class="hljs-built_in">cd</span> clouding.io
</code></pre><p>Antes de seguir, quiero comentarte la estructura de directorios. Dentro del directorio veremos:</p>
<ul>
<li><p><strong>Application</strong>: Aquí es donde reside el código del <strong>API Rest en Symfony 4</strong></p>
</li>
<li><p><strong>Infrastructure</strong>: Aquí es donde esta toda la configuración requerida para levantar nuestros contenedores de <strong>Docker</strong>.</p>
</li>
<li><p><strong>docker-compose-symfony.yml</strong>: Docker compose file para levantar los contenedores para el API (<strong>Nginx y PHP-FPM</strong>).</p>
</li>
<li><p><strong>docker-compose-mysql-redis.yml</strong>: Docker compose file para levantar los contenedores de <strong>MySQL</strong> y <strong>Redis</strong>.</p>
</li>
</ul>
<h2 id="paso-2-verificar-instalacion-de-docker-en-la-instancia">Paso 2: Verificar instalación de Docker en la instancia</h2>
<p>Como hemos creado la instancia de servidor desde la opción que incluye Docker, ya debemos tener instalado lo requerido. Para verificar que todo está en orden ejecutamos:</p>
<pre><code>docker <span class="hljs-comment">--version</span>
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628329109496/zrK5S_dlo.png" alt /></p>
<p>Efectivamente tenemos instalado <strong>Docker</strong>. Necesitamos ahora instalar docker-compose, para ello:</p>
<pre><code><span class="hljs-comment"># Descargamos docker-compose</span>
sudo curl -L https:<span class="hljs-regexp">//github</span>.com/docker/compose/releases/download/<span class="hljs-number">1.24</span>.<span class="hljs-number">1</span>/docker-compose-<span class="hljs-string">`uname -s`</span>-<span class="hljs-string">`uname -m`</span> -o /usr/<span class="hljs-keyword">local</span>/bin/docker-compose

<span class="hljs-comment"># Damos permisos de ejecución</span>
sudo <span class="hljs-keyword">chmod</span> +<span class="hljs-keyword">x</span> /usr/<span class="hljs-keyword">local</span>/bin/docker-compose

<span class="hljs-comment"># Comprobamos versión</span>
docker-compose --version
</code></pre><h2 id="paso-3-crear-contenedores-para-el-api-rest">Paso 3: Crear contenedores para el API Rest</h2>
<pre><code><span class="hljs-selector-tag">docker-compose</span> <span class="hljs-selector-tag">-f</span> <span class="hljs-selector-tag">docker-compose-symfony</span><span class="hljs-selector-class">.yml</span> <span class="hljs-selector-tag">build</span>
</code></pre><p>Esto va a realizar el proceso de Build en donde se descargaran las imágenes de Docker requeridas y se instalarán los recursos esenciales para nuestra configuración requerida.</p>
<p>Una vez que este proceso finalice, procedemos a ejecutar:</p>
<pre><code><span class="hljs-selector-tag">docker-compose</span> <span class="hljs-selector-tag">-f</span> <span class="hljs-selector-tag">docker-compose-symfony</span><span class="hljs-selector-class">.yml</span> <span class="hljs-selector-tag">up</span> <span class="hljs-selector-tag">-d</span>
</code></pre><p>Para comprobar que todo va en orden, podemos visualizar los contenedores que están en ejecución:</p>
<pre><code><span class="hljs-attribute">docker</span> container ls

<span class="hljs-comment">#Otra alternativa es</span>
docker ps
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628329111220/eR0f6sQ38.png" alt /></p>
<p>Podemos ver que nuestros dos contenedores están en ejecución correctamente.</p>
<pre><code>docker <span class="hljs-keyword">exec</span> -it sf4_redis_app bash
</code></pre><p>Y procedemos ahora así a instalar las dependencias del <strong>API Rest en Symfony</strong>:</p>
<pre><code><span class="hljs-attribute">composer</span> install
</code></pre><p>Una vez finalizado esto, podremos verificar que tenemos acceso a nuestro API Rest utilizando Postman o desde cUrl. Para esto debemos realizar una petición <code>**GET</code><strong> al path `</strong>/check<code>**, en mi caso, utilizando el IP de la instancia sería:</code><a target="_blank" href="https://185.166.215.90/check">https://185.166.215.90/check`</a></p>
<p>Deberíamos obtener la respuesta: “ <strong>OK</strong> “</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628329113058/5DKmdUGx6.png" alt /></p>
<p>Por ahora tenemos casi listo nuestro API Rest. Vamos ahora a repetir los mismos pasos para la instancia de MySQL y Redis.</p>
<p>Para ello debemos buscar los datos de acceso (IP, usuario root y contraseña de acceso) de la instancia que hemos llamado “ <strong>Mysql + Redis</strong> “</p>
<p>Una vez dentro de ella mediante <strong>SSH</strong>, vamos a crear el mismo directorio que creamos anteriormente:</p>
<pre><code>mkdir -p /<span class="hljs-keyword">var</span>/www/html
</code></pre><p>Accedemos al directorio:</p>
<pre><code>cd /<span class="hljs-keyword">var</span>/www/html/
</code></pre><p>Ahora repetiremos el “ <strong>Paso 1</strong>” y “ <strong>Paso 2</strong> “ y en este caso, nuestro paso 3 será:</p>
<pre><code><span class="hljs-selector-tag">docker-compose</span> <span class="hljs-selector-tag">-f</span> <span class="hljs-selector-tag">docker-compose-mysql-redis</span><span class="hljs-selector-class">.yml</span> <span class="hljs-selector-tag">build</span>
</code></pre><p>Esto va a realizar el proceso de Build en donde se descargaran las imágenes de Docker requeridas y se instalarán los recursos esenciales para nuestra configuración requerida.</p>
<p>Una vez que este proceso finalice, procedemos a ejecutar:</p>
<pre><code><span class="hljs-selector-tag">docker-compose</span> <span class="hljs-selector-tag">-f</span> <span class="hljs-selector-tag">docker-compose-mysql-redis</span><span class="hljs-selector-class">.yml</span> <span class="hljs-selector-tag">up</span> <span class="hljs-selector-tag">-d</span>
</code></pre><p>Para comprobar que todo va en orden, podemos visualizar los contenedores que están en ejecución:</p>
<pre><code><span class="hljs-attribute">docker</span> container ls

<span class="hljs-comment">#Otra alternativa es</span>
docker ps
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628329114895/8sPwMKONg.png" alt /></p>
<p>Ahora vemos que se han levantados dos contenedores adicionales, el de <strong>MySQL</strong> y el de <strong>Redis</strong>, pero esta es en otra instancia de servidor.</p>
<h2 id="configurar-acceso-privado-entre-instancias">Configurar acceso privado entre instancias</h2>
<p>Debemos entrar desde nuestro panel de <strong>Clouding.io</strong> a cada instancia de servidor, haciendo click en el nombre y seleccionando la pestaña “ <strong>RED</strong> “.</p>
<p>Una vez alli, debemos habilitar la opción “ <strong>Red Privada</strong> “ tal como se muestra a continuación:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628329116604/koieq3U0k.png" alt /></p>
<h2 id="configuracion-adicional">Configuración Adicional</h2>
<p>Necesitamos ahora realizar algunos cambios para que nuestro API Rest funcione como debe ser.</p>
<h2 id="configuracion-mysql">Configuración MySQL</h2>
<p>Procedemos a conectamos al contenedor de <strong>MySQL</strong>:</p>
<pre><code>docker <span class="hljs-keyword">exec</span> -it sf4_redis_mysql bash
</code></pre><p>Nos conectamos a <strong>MySQL</strong>:</p>
<pre><code><span class="hljs-attribute">mysql</span> -uroot -proot
</code></pre><p>Ahora debemos cambiar algunos privilegios a nuestros usuarios debido a que estamos usando <strong>MySQL versión 8</strong>. Para ello ejecutamos las siguientes sentencias <strong>SQL</strong>:</p>
<pre><code><span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">USER</span> <span class="hljs-string">'root'</span>@<span class="hljs-string">'localhost'</span> <span class="hljs-keyword">IDENTIFIED</span> <span class="hljs-keyword">WITH</span> mysql_native_password <span class="hljs-keyword">BY</span> <span class="hljs-string">'root'</span>;

<span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">USER</span> <span class="hljs-string">'root'</span>@<span class="hljs-string">'%'</span> <span class="hljs-keyword">IDENTIFIED</span> <span class="hljs-keyword">WITH</span> mysql_native_password <span class="hljs-keyword">BY</span> <span class="hljs-string">'root'</span>;

<span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">USER</span> <span class="hljs-string">'api'</span>@<span class="hljs-string">'%'</span> <span class="hljs-keyword">IDENTIFIED</span> <span class="hljs-keyword">WITH</span> mysql_native_password <span class="hljs-keyword">BY</span> <span class="hljs-string">'api'</span>;
</code></pre><p>Listo, podemos desconectarnos de <strong>MySQL</strong>, ejecutamos:</p>
<pre><code><span class="hljs-keyword">exit</span>
</code></pre><h2 id="configuracion-api-rest">Configuración API Rest</h2>
<p>Necesitamos nuevamente acceder vía <strong>SSH</strong> a la instancia que hemos llamado: <strong>Api Rest Symfony 4</strong> para configurar nuestro <strong>API Rest</strong> y poder indicarle en los parámetros de nuestro fichero de entornos (.env), cómo acceder a <strong>MySQL</strong> y <strong>Redis</strong>.</p>
<p>Una vez dentro, nos conectamos al contenedor donde reside nuestro <strong>API Rest</strong>:</p>
<pre><code>docker <span class="hljs-keyword">exec</span> -it sf4_redis_app bash
</code></pre><p>Editamos nuestro .env debido a que debemos cambiar los siguientes valores:</p>
<pre><code><span class="hljs-comment"># DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.</span>
<span class="hljs-comment">#</span>
<span class="hljs-comment"># Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex &gt;=1.2).</span>
<span class="hljs-comment"># https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration</span>

<span class="hljs-comment">###&gt; symfony/framework-bundle ###</span>
<span class="hljs-attribute">APP_ENV</span>=dev
<span class="hljs-attribute">APP_SECRET</span>=<span class="hljs-number">70652</span>e<span class="hljs-number">6</span>d<span class="hljs-number">1</span>a<span class="hljs-number">682</span>fac<span class="hljs-number">64</span>b<span class="hljs-number">38</span>a<span class="hljs-number">0</span>d<span class="hljs-number">26</span>d<span class="hljs-number">96</span>fa<span class="hljs-number">6</span>
<span class="hljs-comment">#TRUSTED_PROXIES=127.0.0.1,127.0.0.2</span>
<span class="hljs-comment">#TRUSTED_HOSTS='^localhost|example\.com$'</span>
<span class="hljs-comment">###&lt; symfony/framework-bundle ###</span>

<span class="hljs-comment">###&gt; doctrine/doctrine-bundle ###</span>
<span class="hljs-comment"># Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url</span>
<span class="hljs-comment"># For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db"</span>
<span class="hljs-comment"># For a PostgreSQL database, use: "postgresql://db_user:db_password@127.0.0.1:5432/db_name?serverVersion=11"</span>
<span class="hljs-comment"># IMPORTANT: You MUST also configure your db driver and server_version in config/packages/doctrine.yaml</span>
<span class="hljs-attribute">DATABASE_URL</span>=mysql://api:api@IP_PRIVADA_INSTANCIA:<span class="hljs-number">3306</span>/api_db
<span class="hljs-comment">###&lt; doctrine/doctrine-bundle ###</span>

<span class="hljs-comment">###&gt; snc/redis-bundle ###</span>
<span class="hljs-comment"># passwords that contain special characters (@, %, :, +) must be urlencoded</span>
<span class="hljs-attribute">REDIS_URL</span>=redis://IP_PRIVADA_INSTANCIA
<span class="hljs-comment">###&lt; snc/redis-bundle ###</span>
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628329118109/XHtlcQ6Q3.png" alt /></p>
<p>En mi caso, mi fichero .env quedó de la siguiente forma:</p>
<pre><code><span class="hljs-comment"># DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.</span>
<span class="hljs-comment">#</span>
<span class="hljs-comment"># Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex &gt;=1.2).</span>
<span class="hljs-comment"># https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration</span>

<span class="hljs-comment">###&gt; symfony/framework-bundle ###</span>
<span class="hljs-attribute">APP_ENV</span>=dev
<span class="hljs-attribute">APP_SECRET</span>=<span class="hljs-number">70652</span>e<span class="hljs-number">6</span>d<span class="hljs-number">1</span>a<span class="hljs-number">682</span>fac<span class="hljs-number">64</span>b<span class="hljs-number">38</span>a<span class="hljs-number">0</span>d<span class="hljs-number">26</span>d<span class="hljs-number">96</span>fa<span class="hljs-number">6</span>
<span class="hljs-comment">#TRUSTED_PROXIES=127.0.0.1,127.0.0.2</span>
<span class="hljs-comment">#TRUSTED_HOSTS='^localhost|example\.com$'</span>
<span class="hljs-comment">###&lt; symfony/framework-bundle ###</span>

<span class="hljs-comment">###&gt; doctrine/doctrine-bundle ###</span>
<span class="hljs-comment"># Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url</span>
<span class="hljs-comment"># For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db"</span>
<span class="hljs-comment"># For a PostgreSQL database, use: "postgresql://db_user:db_password@127.0.0.1:5432/db_name?serverVersion=11"</span>
<span class="hljs-comment"># IMPORTANT: You MUST also configure your db driver and server_version in config/packages/doctrine.yaml</span>
<span class="hljs-attribute">DATABASE_URL</span>=mysql://api:api@ <span class="hljs-number">10.20.10.5:3306</span>/api_db
<span class="hljs-comment">###&lt; doctrine/doctrine-bundle ###</span>

<span class="hljs-comment">###&gt; snc/redis-bundle ###</span>
<span class="hljs-comment"># passwords that contain special characters (@, %, :, +) must be urlencoded</span>
<span class="hljs-attribute">REDIS_URL</span>=redis://<span class="hljs-number">10.20.10.5</span>
<span class="hljs-comment">###&lt; snc/redis-bundle ###</span>
</code></pre><h2 id="migraciones-de-doctrine">Migraciones de Doctrine</h2>
<p>Necesitamos ahora ejecutar las migraciones de <strong>Doctrine</strong> en nuestro <strong>API Rest</strong> para crear la tabla necesaria de productos:</p>
<p>Estando conectados al contenedor “ <strong>sf4_redis_app</strong> “ ejecutamos ahora lo siguiente:</p>
<pre><code><span class="hljs-selector-tag">php</span> <span class="hljs-selector-tag">bin</span>/<span class="hljs-selector-tag">console</span> <span class="hljs-selector-tag">doc</span><span class="hljs-selector-pseudo">:mig</span><span class="hljs-selector-pseudo">:mig</span>
</code></pre><p>Nos mostrará un mensaje de advertencia y nos solicitará que confirmemos la ejecución del proceso, por lo que vamos a escribir “Y” para continuar.</p>
<p>Y con esto ya tendríamos desplegada nuestro API Rest en contenedores utilizando la plataforma <strong>Clouding.io</strong></p>
<h2 id="hasta-ahora-que-hemos-logrado-hacer">Hasta ahora, ¿Qué hemos logrado hacer?</h2>
<ul>
<li><p>Aprendimos a conocer como utilizar la plataforma de clouding.io</p>
</li>
<li><p>Aprendimos a crear dos instancias de servidor.</p>
</li>
<li><p>Vimos como instalar lo necesario para desplegar nuestros contenedores.</p>
</li>
<li><p>Hemos desplegado dos contenedores, uno con <strong>nginx</strong> y otro con <strong>php-fpm</strong> en nuestra instancia del <strong>API Rest</strong>.</p>
</li>
<li><p>Desplegamos dos contenedores, uno con <strong>MySQL</strong> y otro para <strong>Redis</strong> en nuestra instancia destinada para los datos.</p>
</li>
<li><p>Hemos aprendido cómo configurar las instancias para que puedan comunicarse localmente entre sí mediante la <strong>red</strong> <strong>privada</strong>.</p>
</li>
<li><p>Hemos configurado nuestro proyecto en <strong>Symfony 4</strong> para que se conecte a los contenedores de <strong>MySQL </strong>y <strong>Redis</strong>. A su vez hemos hecho las migraciones respectivas.</p>
</li>
</ul>
<h2 id="que-sigue-ahora">¿Que sigue ahora?</h2>
<p>Lo siguiente será probar nuestra <strong>API Rest</strong> en <strong>Symfony 4</strong> con <strong>Redis</strong> para el <strong>cache</strong> y <strong>MySQL</strong> para albergar los datos.</p>
<p>Todo el código de la aplicación en <strong>Symfony 4</strong> + <strong>Redis</strong> lo puedes descargar desde <a target="_blank" href="https://github.com/franciscougalde-com/sf4-mysql-redis-example.git">**mi repositorio</a>**</p>
<h2 id="como-probar-el-api-rest">¿Cómo probar el API Rest?</h2>
<p>Para demostrar cómo funciona el despliegue de los contenedores en dos instancias separadas de <strong>Couding.io</strong>, he desarrollado un endpoint que permite consultar la lista de productos.</p>
<p>Si los productos no están en cache, se consultan de la base de datos <strong>MySQL</strong> y se cachean en <strong>Redis</strong> con un tiempo de expiración de una hora.</p>
<p>Para poder conocer si los datos vienen de la cache de <strong>Redis</strong> o de <strong>Mysql</strong>, la respuesta de la petición incluye en su cuerpo el parámetro “ <strong>source</strong>” indicando si los datos provienen de <strong>MySQL</strong> o <strong>Redis</strong>.</p>
<p>Adicionalmente incorporé el endpoint para añadir mas productos y poder ver el funcionamiento un poco más claro, ya que una vez cacheado los productos, podemos añadir unos cuantos más y no los veremos en la respuesta hasta tanto invalidemos el cache ó el cache expire (en una hora para nuestro caso).</p>
<p>Para probar el <strong>API Rest</strong> puedes hacer las siguientes peticiones:</p>
<p><strong>Método</strong>: <strong>GET</strong>
<strong>Url</strong>: <a target="_blank" href="https://ip_o_host_publico_de_instancia_symfony/check">https://ip_o_host_publico_de_instancia_symfony/check</a>
Este endpoint te permite verificar que tienes acceso al <strong>API Rest</strong>.</p>
<p><strong>Método</strong>: <strong>GET</strong>
<strong>Url</strong>: <a target="_blank" href="https://ip_o_host_publico_de_instancia_symfony/api/v1/products">https://ip_o_host_publico_de_instancia_symfony/api/v1/products</a>
Nos va a listar los productos que tengamos en <strong>MySQL</strong> ó <strong>Redis</strong></p>
<p><strong>Método</strong>: <strong>POST</strong>
<strong>Url</strong>: <a target="_blank" href="https://ip_o_host_publico_de_instancia_symfony/api/v1/products">https://ip_o_host_publico_de_instancia_symfony/api/v1/products</a>
Nos permite añadir un producto a la Base de Datos.
<strong>Body</strong>: Debes enviar un <strong>json</strong> en el cuerpo de la petición</p>
<pre><code><span class="hljs-comment">#Body para añadir un producto nuevo</span>
{
    <span class="hljs-string">"name"</span>:<span class="hljs-string">"Product 1"</span>,
    <span class="hljs-string">"price"</span>:<span class="hljs-number">1256</span>,
    <span class="hljs-string">"stock"</span>:<span class="hljs-number">111</span>
}
</code></pre><p><strong>Método</strong>: <strong>POST</strong>
<strong>Url</strong>: <a target="_blank" href="https://ip_o_host_publico_de_instancia_symfony/api/v1/products/cache-invalidate">https://ip_o_host_publico_de_instancia_symfony/api/v1/products/cache-invalidate</a>
Nos permite invalidar la cache de redis para poder demostrar su funcionamiento.</p>
<h2 id="pila-de-pruebas-para-demostrar-el-funcionamiento">Pila de Pruebas para demostrar el funcionamiento</h2>
<ol>
<li><p>Realiza una petición al Post para añadir unos 3 o 4 productos usando el <strong>body</strong> indicado.</p>
</li>
<li><p>Realiza la petición al listado de productos y verás que la primera vez los datos vienen desde la base de datos <strong>MySQL</strong>.</p>
</li>
<li><p>Nuevamente ejecuta la misma petición del listado de productos y verás que provienen de <strong>Redis</strong> puesto que en la anterior petición fueron cacheados.</p>
</li>
<li><p>Prueba añadiendo unos productos más.</p>
</li>
<li><p>Intenta nuevamente obtener la lista de productos, verás que si no ha pasado 1 hora desde que la lista inicial ha sido cacheada, los productos que añadas luego, no aparecerán en la petición del listado de productos.</p>
</li>
<li><p>Ahora ejecuta la petición para invalidar la cache.</p>
</li>
<li><p>Prueba nuevamente obtener el listado de productos, verás que ahora vendrán nuevamente desde <strong>MySQL</strong> y aparecerán los últimos productos que añadiste y que no habían sido cacheados.</p>
</li>
</ol>
<p>Recuerda que si tienes alguna sugerencia o pregunta, no dudes en dejar tus comentarios al final del post.</p>
<p>Si te gustó este post, ayúdame a que pueda servirle a muchas más personas, compartiendo mis contenidos en tus redes sociales.</p>
<p>Espero que este post haya sido de gran ayuda para ti, y como siempre, cualquier inquietud o duda que tengas, puedes contactarme por cualquiera de las vías disponibles, o dejando tus comentarios al final de este post. También puedes sugerir que temas o post te gustaría leer a futuro.</p>
]]></content:encoded></item><item><title><![CDATA[Factory Pattern en PHP y como usarlo]]></title><description><![CDATA[*Importante: No confundir el Factory Pattern con el patrón Abstract Factory, aunque del mismo tipo, resuelven distintos problemas de distinta forma.
A considerar…*

El patrón de diseño Factory viene a solucionar los inconvenientes con la creación o i...]]></description><link>https://franciscougalde.com/factory-pattern-en-php-y-como-usarlo</link><guid isPermaLink="true">https://franciscougalde.com/factory-pattern-en-php-y-como-usarlo</guid><category><![CDATA[PHP]]></category><category><![CDATA[design patterns]]></category><category><![CDATA[clean code]]></category><category><![CDATA[software development]]></category><category><![CDATA[software architecture]]></category><dc:creator><![CDATA[Francisco Ugalde]]></dc:creator><pubDate>Fri, 18 Oct 2019 06:58:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628841028224/4BjlCmU-wZ.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong>*Importante: </strong>No confundir el <strong>Factory</strong> <strong>Pattern</strong> con el patrón <strong>Abstract Factory,</strong> aunque del mismo tipo, resuelven distintos problemas de distinta forma.<em>
</em>A considerar…*</p>
</blockquote>
<p>El patrón de diseño Factory viene a solucionar los inconvenientes con la creación o instanciación de nuestros objetos. La idea es encapsular u ocultar al cliente los detalles internos para la creación de ciertos objetos, o dicho de una mejor manera:</p>
<blockquote>
<p><em>Desacoplar la lógica de creación de la lógica de negocio, evitando al cliente conocer detalles de la instanciación de los objetos de los que depende.</em>
<em>Propósito del patrón</em></p>
</blockquote>
<h2 id="implementacion-del-factory-pattern">Implementación del Factory Pattern</h2>
<h2 id="caso-de-ejemplo">Caso de ejemplo</h2>
<p>Supongamos que necesitamos desarrollar un sistema para una tienda apple el cual permita mostrar la ficha informativa de cada ordenador fabricado por Apple. Una primera aproximación del código sería:</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AppleTechnicalSheet</span>

<span class="hljs-title">class</span> <span class="hljs-title">AppleTechnicalSheet</span>
</span>{
    <span class="hljs-keyword">const</span> MACBOOK = <span class="hljs-string">'MAC'</span>;
    <span class="hljs-keyword">const</span> MACBOOK_AIR = <span class="hljs-string">'MACAIR'</span>;
    <span class="hljs-keyword">const</span> MACBOOK_PRO = <span class="hljs-string">'MACPRO'</span>;
    <span class="hljs-keyword">const</span> IMAC = <span class="hljs-string">'IMAC'</span>;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getTechnicalSheet</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $model</span>)
    </span>{
        <span class="hljs-keyword">switch</span> ($model) {
            <span class="hljs-keyword">case</span> <span class="hljs-built_in">self</span>::MACBOOK:
                $processor = <span class="hljs-string">'Intel Core i5'</span>;
                $model = <span class="hljs-string">'Macbook'</span>;
                $cores = <span class="hljs-number">4</span>;
                $ssd = <span class="hljs-string">'256GB'</span>;
                $memory = <span class="hljs-string">'4GB'</span>; 
                <span class="hljs-keyword">break</span>;

            <span class="hljs-keyword">case</span> <span class="hljs-built_in">self</span>::MACBOOK_AIR:
                $processor = <span class="hljs-string">'Intel Core i3'</span>;
                $model = <span class="hljs-string">'Macbook Air'</span>;
                $cores = <span class="hljs-number">2</span>;
                $ssd = <span class="hljs-string">'128GB'</span>;
                $memory = <span class="hljs-string">'4GB'</span>;
                <span class="hljs-keyword">break</span>;

            <span class="hljs-keyword">case</span> <span class="hljs-built_in">self</span>::MACBOOK_PRO:
                $processor = <span class="hljs-string">'Intel Core i7'</span>;
                $model = <span class="hljs-string">'Macbook Pro'</span>;
                $cores = <span class="hljs-number">6</span>;
                $ssd = <span class="hljs-string">'512GB'</span>;
                $memory = <span class="hljs-string">'16GB'</span>;
                <span class="hljs-keyword">break</span>;

            <span class="hljs-keyword">case</span> <span class="hljs-built_in">self</span>::IMAC:
                $processor = <span class="hljs-string">'Intel Core i7'</span>;
                $model = <span class="hljs-string">'iMac'</span>;
                $cores = <span class="hljs-number">6</span>;
                $ssd = <span class="hljs-string">'512GB'</span>;
                $memory = <span class="hljs-string">'8GB'</span>;
                <span class="hljs-keyword">break</span>;

            <span class="hljs-keyword">default</span>:
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">InvalidArgumentException</span>(<span class="hljs-string">"The model you requested doesn't exist"</span>);
        }

        $format = <span class="hljs-string">'Model: %s \n Processor: %s \n Cores: %d \n SSD: %s \n Memory: %s'</span>;

        <span class="hljs-keyword">return</span> sprintf($format, $model, $processor, $cores, $ssd, $memory);
    }
}
</code></pre><p>Como se puede observar, esta implementación contiene evidentes problemas y el principal es el uso del <strong>switch case</strong> encargado de gestionar el modelo a mostrar.</p>
<p>Ya que si a futuro necesitamos añadir nuevos modelos, habra que estar editando el switch para añadirlos por lo que esta implementación no es limpia pero si dependiente de muchísimo mantenimiento.</p>
<p>Ademas de que visto de otra forma, estaríamos rompiendo el principio de responsabilidad única (Single Responsability Principle) de <strong>SOLID</strong> puesto que una misma clase esta gestionando lo que debería estar separado en varias clases, en nuestro ejemplo, una clase por modelo.</p>
<h2 id="implementando-factory-pattern">Implementando Factory Pattern</h2>
<p>Los pasos a seguir para implementar en este caso el patrón Factory son:</p>
<ul>
<li><p><strong>Encapsular en objetos la información relativa a cada modelo de ordenador.</strong> No tiene sentido el tener esas constantes y variables dentro del switch.</p>
</li>
<li><p><strong>En pro de estandarizar las acciones a realizar, crear una interfaz que todos los objetos implementen. </strong>Debido a que los rubros de información a mostrar son iguales, es preferible que todos implementen una misma interfaz que le indique a cada clase qué métodos debe definir.</p>
</li>
<li><p><strong>Extraer la lógica de creación a una factoría.</strong> El cliente (la ficha técnica en este caso) no tiene por qué conocer cómo se instancian estos objetos, no es su responsabilidad, y además no es reutilizable. Saquemos ese código a una clase nueva.</p>
</li>
<li><p><strong>Usar la factoría en la ficha técnica.</strong> Hagamos uso de la factoría en el cliente.</p>
</li>
</ul>
<h3 id="modelfactory-class">ModelFactory Class</h3>
<pre><code>ModelFactory <span class="hljs-class"><span class="hljs-keyword">Class</span>

<span class="hljs-title">class</span> <span class="hljs-title">ModelFactory</span>
</span>{
    <span class="hljs-keyword">const</span> MACBOOK = <span class="hljs-string">'MAC'</span>;
    <span class="hljs-keyword">const</span> MACBOOK_AIR = <span class="hljs-string">'MACAIR'</span>;
    <span class="hljs-keyword">const</span> MACBOOK_PRO = <span class="hljs-string">'MACPRO'</span>;
    <span class="hljs-keyword">const</span> IMAC = <span class="hljs-string">'IMAC'</span>;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">create</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $model</span>)
    </span>{
        <span class="hljs-keyword">switch</span> ($model) {
            <span class="hljs-keyword">case</span> <span class="hljs-built_in">self</span>::MACBOOK:
                <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Macbook();

            <span class="hljs-keyword">case</span> <span class="hljs-built_in">self</span>::MACBOOK_AIR:
                <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> MacbookAir();

            <span class="hljs-keyword">case</span> <span class="hljs-built_in">self</span>::MACBOOK_PRO:
                <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> MacbookPro();

            <span class="hljs-keyword">case</span> <span class="hljs-built_in">self</span>::IMAC:
                <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Imac();

            <span class="hljs-keyword">default</span>:
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">InvalidArgumentException</span>(<span class="hljs-string">"The model you requested doesn't exist"</span>);
        }
    }
}
</code></pre><h3 id="technicalsheetinterface-interface">TechnicalSheetInterface Interface</h3>
<pre><code><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">TechnicalSheetInterface</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getModel</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span></span>;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getProcessor</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span></span>;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getCores</span>(<span class="hljs-params"></span>): <span class="hljs-title">int</span></span>;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getSsd</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span></span>;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getMemory</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span></span>;
}
</code></pre><h3 id="technicalsheet-class">TechnicalSheet Class</h3>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TechnicalSheet</span>
</span>{
    <span class="hljs-keyword">private</span> $modelFactory;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">ModelFactory $modelFactory</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;modelFactory = $modelFactory;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getTechnicalSheet</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $model</span>)
    </span>{
        <span class="hljs-comment">/** <span class="hljs-doctag">@var</span> TechnicalSheetInterface $model */</span>
        $model = <span class="hljs-keyword">$this</span>-&gt;modelFactory-&gt;create($model);

        $format = <span class="hljs-string">'Model: %s \n Processor: %s \n Cores: %d \n SSD: %s \n Memory: %s'</span>;

        <span class="hljs-keyword">return</span> sprintf(
            $format,
            $model-&gt;getModel(),
            $model-&gt;getProcessor(),
            $model-&gt;getCores(),
            $model-&gt;getSsd(),
            $model-&gt;getMemory()
        );
    }
}
</code></pre><h3 id="macbook-class">Macbook Class</h3>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Macbook</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">TechnicalSheetInterface</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getModel</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">'Macbook'</span>;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getProcessor</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">'Intel Core i5'</span>;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getCores</span>(<span class="hljs-params"></span>): <span class="hljs-title">int</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-number">4</span>;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getSsd</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">'256GB'</span>;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getMemory</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">'4GB'</span>;
    }
}
</code></pre><h3 id="macbookair-class">MacbookAir Class</h3>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MacbookAir</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">TechnicalSheetInterface</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getModel</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">'Macbook Air'</span>;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getProcessor</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">'Intel Core i3'</span>;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getCores</span>(<span class="hljs-params"></span>): <span class="hljs-title">int</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-number">2</span>;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getSsd</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">'128GB'</span>;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getMemory</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">'4GB'</span>;
    }
}
</code></pre><h3 id="macbook-pro-class">Macbook Pro Class</h3>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MacbookPro</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">TechnicalSheetInterface</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getModel</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">'Macbook Pro'</span>;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getProcessor</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">'Intel Core i7'</span>;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getCores</span>(<span class="hljs-params"></span>): <span class="hljs-title">int</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-number">6</span>;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getSsd</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">'512GB'</span>;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getMemory</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">'16GB'</span>;
    }
}
</code></pre><h3 id="imac-class">IMac Class</h3>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IMac</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">TechnicalSheetInterface</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getModel</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">'iMac'</span>;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getProcessor</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">'Intel Core i7'</span>;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getCores</span>(<span class="hljs-params"></span>): <span class="hljs-title">int</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-number">6</span>;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getSsd</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">'256GB'</span>;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getMemory</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">'8GB'</span>;
    }
}
</code></pre><p>Resumamos un poco lo implementado</p>
<ul>
<li><p>Definimos la interfaz <strong>TechnicalSheetInterface</strong>, que permite definir los getters necesarios para generar la información técnica de cada modelo.</p>
</li>
<li><p>Se ha creado una clase por cada uno de los modelos de ordenadores disponibles.</p>
</li>
<li><p>Hemos creado una clase <strong>ModelFactory </strong>que se encarga de construir el modelo según el código que se envíe y de lanzar una excepción en caso de no existir el modelo que se intenta mostrar.</p>
</li>
<li><p>El cliente <strong>TechnicalSheet</strong> ahora recibe en el constructor la factoría y hace uso de ella para obtener un objeto que implementa <strong>TechnicalSheetInterface</strong> con el que muestra la ficha técnica correspondiente.</p>
</li>
</ul>
<h2 id="ventajas-del-factory-pattern">Ventajas del Factory Pattern</h2>
<ul>
<li><p>La factoría es altamente reutilizable, solo hay que pasarla como dependencia.</p>
</li>
<li><p>El testing del cliente es mucho más sencillo, podemos usar mocks para la factoría y simular cualquier tipo de repuesta por parte de la misma, permitiendo testear todos los casos de uso posibles.</p>
</li>
<li><p>Si queremos añadir un nuevo modelo, solo hay que editar la factoría y añadirlo ahí, pasará a estar disponible para todos los usuarios de la factoría sin tener que replicar código.</p>
</li>
</ul>
<h2 id="contras-del-factory-pattern">Contras del Factory Pattern</h2>
<ul>
<li><strong>En este ejemplo</strong>, si la cantidad de opciones crece en exceso, la factoría puede llegar a ser una clase difícil de mantener y habría que encontrar otras alternativas al switch como por ejemplo utilizar la clase ReflectionClass de PHP para instanciar la clase correspondiente basado en el nombre del modelo de ordenador a mostrar.</li>
</ul>
<h2 id="consideraciones-finales">Consideraciones finales</h2>
<p>Abstraer al cliente de la creación de los objetos de los que depende es un principio básico en la creación de software de calidad. Esto nos permite cumplir con dos principios <strong>SOLID</strong> de un plumazo y además seguir uno de los principios de la programación orientada a objetos: la encapsulación de los datos en objetos.</p>
<p>Recuerda que si tienes alguna sugerencia o pregunta, no dudes en dejar tus comentarios al final del post.</p>
<p>Si te gustó este post, ayúdame a que pueda servirle a muchas más personas, compartiendo mis contenidos en tus redes sociales.</p>
<p>Espero que este post haya sido de gran ayuda para ti, y como siempre, cualquier inquietud o duda que tengas, puedes contactarme por cualquiera de las vías disponibles, o dejando tus comentarios al final de este post. También puedes sugerir que temas o post te gustaría leer a futuro.</p>
]]></content:encoded></item><item><title><![CDATA[Tell Don’t Ask: Principios de POO en PHP]]></title><description><![CDATA[Tell Don’t ask es un principio de la programación orientada a objetos ( POO) que nos recuerda que no tenemos que usar los objetos para pedirles cosas o datos primero y según la información que nos devuelven tomar decisiones
Por el contrario, el princ...]]></description><link>https://franciscougalde.com/tell-dont-ask-principios-de-poo-en-php</link><guid isPermaLink="true">https://franciscougalde.com/tell-dont-ask-principios-de-poo-en-php</guid><category><![CDATA[PHP]]></category><category><![CDATA[oop]]></category><category><![CDATA[clean code]]></category><category><![CDATA[software architecture]]></category><category><![CDATA[software development]]></category><dc:creator><![CDATA[Francisco Ugalde]]></dc:creator><pubDate>Fri, 11 Oct 2019 15:08:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628841044996/lKADzXrQU.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Tell Don’t ask</strong> es un principio de la programación orientada a objetos ( <strong>POO</strong>) que nos recuerda que no tenemos que usar los objetos para pedirles cosas o datos primero y según la información que nos devuelven tomar decisiones</p>
<p>Por el contrario, el principio nos sugiere es decirles a los objetos que hagan cosas y estos objetos internamente tomaran sus propias decisiones según de su estado actual.</p>
<p>Este principio encaja perfectamente con la idea de que un objeto se define por su comportamiento; y además es fundamental para sacar provecho al <strong>polimorfismo</strong> y la inversión de control.</p>
<p>Es decir si nos dedicamos a preguntar y tomar nosotros las decisiones estaremos acoplándonos, será prácticamente imposible hacer cambios al objeto en un futuro.</p>
<p>Estaríamos también incumpliendo el <strong>“<em>principio Open/Close</em></strong>” de los “<strong><em>principios de SOLID</em></strong>”, nuestro sistema será más difícil de mantener, y por lo tanto poco escalable.</p>
<p>Al ser expuesto el estado de una clase a las demás para que pueda ser manipulada estamos violando su encapsulamiento y por ende moviendo las responsabilidades a las clases de mayor nivel.</p>
<h2 id="usas-getters-y-setters-en-tus-clases">¿Usas GETTERS y SETTERS en tus Clases?</h2>
<p>Si tu respuesta es sí lo mas probable es que estés inclumpliendo el principio “ <strong>Tell Don’t Ask</strong> “. Ya que por lo general tendemos a usar estos métodos de nuestras clases para asignar y devolver datos.</p>
<p>Por lo que entonces, desde las clases desde donde instanciemos los objetos, seguramente estaremos haciendo uso de un getter para comprobar su estado o valor, y dependiendo del esto, hacer uso del setter para modificar su estado.</p>
<p>Estaríamos también delegando al controlador aplicar reglas y validaciones que quizás sean de negocio y por ende deban encapsularse en nuestros objetos de clase.</p>
<p>Para solucionar esto, lo mejor sería utilizar métodos semánticos y aplicar el principio de “ <strong>Tell Don´t Ask</strong> “ para delegar la responsabilidad de validaciones y comprobaciones al objeto como tal, manteniendo entonces nuestros objetos encapsulados.</p>
<h2 id="ejemplo-de-violacion-del-principio-tell-dont-ask">Ejemplo de violación del principio Tell Don´t Ask</h2>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">InvoiceController</span> 
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">payAction</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-comment">// ...     </span>
        $userBalance = $user-&gt;getBalance();
        <span class="hljs-keyword">if</span> ($userBalance &lt; $invoiceTotal) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NotEnoughFundsException();
        }

        $newBalance = $userBalance - $invoiceTotal;
        $user-&gt;setBalance($newBalance);

        <span class="hljs-comment">// ...</span>
    }
}
</code></pre><p>Podemos ver en el ejemplo anterior, usamos un getter (<code>$user-&amp;gt;getBalance()</code>) para obtener un valor, y luego en base a ese valor, del lado del controlador, realizamos comprobaciones. Aquí estamos violando el principio.</p>
<h2 id="ejemplo-correcto-del-principio-tell-dont-ask">Ejemplo correcto del principio Tell Don´t Ask</h2>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">InvoiceController</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">payAction</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-comment">// ...</span>
        <span class="hljs-keyword">try</span> {
            $user-&gt;payInvoice($invoice);
        } <span class="hljs-keyword">catch</span> (NotEnoughFundsException $e) {
            <span class="hljs-comment">// ...</span>
        }
        <span class="hljs-comment">// ...</span>
    }
}
</code></pre><p>Y en el objeto user, dentro del método “<code>**payInvoice(...)</code>**" realizar las comprobaciones pertinentes, y si todo va bien, procedemos a realizar el action requerido, de lo contrario, arrojar una excepción la cual debe ser controlada en el lado del controlador.</p>
<p>Y de esta forma podemos entonces aplicar este principio en nuestros desarrollo para cumplir con una arquitectura de código limpia y acoplándonos a los principios de la POO.</p>
<p>Recuerda que si tienes alguna sugerencia o pregunta, no dudes en dejar tus comentarios al final del post.</p>
<p>Si te gustó este post, ayúdame a que pueda servirle a muchas más personas, compartiendo mis contenidos en tus redes sociales.</p>
<p>Espero que este post haya sido de gran ayuda para ti, y como siempre, cualquier inquietud o duda que tengas, puedes contactarme por cualquiera de las vías disponibles, o dejando tus comentarios al final de este post. También puedes sugerir que temas o post te gustaría leer a futuro.</p>
]]></content:encoded></item><item><title><![CDATA[Symfony: ¿Como usar el componente Mailer?]]></title><description><![CDATA[Componente Mailer de Symfony

El componente de Symfony fue introducido en la versión 4.3 y aún esta considerado un feature experimental
Nota a considerar antes de comenzar a usarlo en producción.

Otra de las necesidades más comunes en cada aplicació...]]></description><link>https://franciscougalde.com/symfony-como-usar-el-componente-mailer</link><guid isPermaLink="true">https://franciscougalde.com/symfony-como-usar-el-componente-mailer</guid><category><![CDATA[Symfony]]></category><category><![CDATA[framework]]></category><category><![CDATA[software development]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[software]]></category><dc:creator><![CDATA[Francisco Ugalde]]></dc:creator><pubDate>Thu, 03 Oct 2019 16:03:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628841068115/n4a91h9GC3.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="componente-mailer-de-symfony">Componente Mailer de Symfony</h2>
<blockquote>
<p><em>El componente de <strong>Symfony</strong> fue introducido en la versión <strong>4.3</strong> y aún esta considerado un feature experimental</em>
<em>Nota a considerar antes de comenzar a usarlo en producción.</em></p>
</blockquote>
<p>Otra de las necesidades más comunes en cada aplicación que desarrollamos, es el uso de una librería que nos provea un cliente de correo.</p>
<p><strong>Symfony</strong>, como era de esperarse, nos provee siempre de herramientas y componente muy útiles que nos permiten desarrollar nuestras aplicaciones con una garantía de calidad impecable.</p>
<p>Es por esto, que quiero mostrarte como funciona este nuevo <strong>componente</strong> que se introduce en el <strong>framework</strong> desde la versión de <strong>Symfony 4.3</strong></p>
<p>Vale la pena destacar que el componente es quién permite crear los mensajes de correo a enviar, y <strong>Mailer</strong> es quien realmente se encarga de enviarlos.</p>
<p>Los mensajes se envían mediante <em>“<strong>transports</strong>”</em>, que pueden ser desde un servidor <strong>SMTP</strong> local hasta un servicio de terceros para envío masivo de emails.</p>
<p>Este componente nos provee de integración con los siguientes servicios: Amazon SES, MailChimp, Mailgun, Gmail, Postmark y SendGrid. Cada uno de estos se instala por separado así que para este post te mostraré un ejemplo de como usar en tu aplicación Amazon SES.</p>
<h2 id="instalacion-del-componente-mailer-para-amazon-ses">Instalación del componente Mailer para Amazon SES</h2>
<pre><code>composer <span class="hljs-keyword">require</span> symfony/amazon-mailer
</code></pre><p>Este paquete, al terminar su instalación, añade algunas variables a nuestro fichero de entorno <strong>.env</strong> para poder configurar los parámetros requeridos para su funcionamiento:</p>
<pre><code><span class="hljs-comment"># .env</span>
<span class="hljs-attr">AWS_ACCESS_KEY</span>=...
<span class="hljs-attr">AWS_SECRET_KEY</span>=...
<span class="hljs-attr">MAILER_DSN</span>=smtp://<span class="hljs-variable">$AWS_ACCESS_KEY</span>:<span class="hljs-variable">$AWS_SECRET_KEY</span>@ses
</code></pre><p>Y con esto ya tenemos todo listo. Lo siguiente es inyectar el servicio de email en cualquier parte donde sea requerido gracias al <a target="_blank" href="https://symfony.com/doc/current/service_container/autowiring.html">**autowiring</a><strong> de </strong>symfony**, añadiendo tan solo el argumento <code>MailerInterface</code> en el constructor de tu clase eso es todo</p>
<pre><code><span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mailer</span>\<span class="hljs-title">MailerInterface</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mime</span>\<span class="hljs-title">Email</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SomeService</span>
</span>{
    <span class="hljs-keyword">private</span> $mailer;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">MailerInterface $mailer</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;mailer = $mailer;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendNotification</span>(<span class="hljs-params"></span>)
    </span>{
        $email = (<span class="hljs-keyword">new</span> Email())
            -&gt;from(<span class="hljs-string">'hello@example.com'</span>)
            -&gt;to(<span class="hljs-string">'you@example.com'</span>)
            -&gt;subject(<span class="hljs-string">'Time for Symfony Mailer!'</span>)
            -&gt;text(<span class="hljs-string">'Sending emails is fun again!'</span>)
            -&gt;html(<span class="hljs-string">'&lt;p&gt;See Twig integration for better HTML integration!&lt;/p&gt;'</span>);

        <span class="hljs-keyword">$this</span>-&gt;mailer-&gt;send($email);
    }
}
</code></pre><p>Cuando llamas a <code>$this-&amp;gt;mailer-&amp;gt;send($email)</code>, el mensaje se envía inmediatamente. Si quieres mejorar el rendimiento, usa el <a target="_blank" href="https://www.franciscougalde.com/2019/07/17/symfony-como-usar-el-componente-messenger-parte-1/">componente Messenger</a> para enviar los mensajes de manera asíncrona. Lee ademas <a target="_blank" href="https://symfony.com/doc/current/mailer.html#sending-messages-async">este artículo de la documentación de Symfony</a> para aprender más sobre cómo hacerlo.</p>
<p>Es todo por ahora con todo lo relacionado con este maravilloso componente de <strong>Symfony</strong>. Estaré publicando actualizaciones a medida que el componente vaya incorporando nuevas funcionalidades.</p>
<p>Recuerda que si tienes alguna sugerencia o pregunta, no dudes en dejar tus comentarios al final del post.</p>
<p>Si te gustó este post, ayúdame a que pueda servirle a muchas más personas, compartiendo mis contenidos en tus redes sociales.</p>
<p>Espero que este post haya sido de gran ayuda para ti, y como siempre, cualquier inquietud o duda que tengas, puedes contactarme por cualquiera de las vías disponibles, o dejando tus comentarios al final de este post. También puedes sugerir que temas o post te gustaría leer a futuro.</p>
]]></content:encoded></item><item><title><![CDATA[Patrón de diseño Decorator en PHP]]></title><description><![CDATA[Patrón de diseño DECORATOR en PHP
En este post quiero enseñarte otro patrón de diseño que utilizo comúnmente en los proyectos que he tenido la oportunidad de trabajar y es el patrón de diseño DECORATOR o Decorador.
Este patrón nos permite resolver el...]]></description><link>https://franciscougalde.com/patron-de-diseno-decorator-en-php</link><guid isPermaLink="true">https://franciscougalde.com/patron-de-diseno-decorator-en-php</guid><category><![CDATA[PHP]]></category><category><![CDATA[design patterns]]></category><category><![CDATA[clean code]]></category><category><![CDATA[software development]]></category><category><![CDATA[software architecture]]></category><dc:creator><![CDATA[Francisco Ugalde]]></dc:creator><pubDate>Thu, 26 Sep 2019 05:31:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628841096201/uVBzMQ9oG.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="patron-de-diseno-decorator-en-php">Patrón de diseño DECORATOR en PHP</h2>
<p>En este post quiero enseñarte otro patrón de diseño que utilizo comúnmente en los proyectos que he tenido la oportunidad de trabajar y es el<strong> patrón de diseño DECORATOR </strong>o Decorador.</p>
<p>Este patrón nos permite resolver el problema de agregar comportamiento o funcionalidad específica a los objetos de una clase. La POO nos permite recurrir a la herencia cuando se trata de añadir funcionalidad extra a nuestra clase.</p>
<p>Pero, el problema radica en que no podemos heredar de más de una clase, es decir, dada una clase C, no podrá heredar a la vez de una clase A y B.</p>
<p>Es por eso que el patrón de diseño <strong>Decorator</strong> nos permite añadir comportamiento específico a los objetos de una clase sin tener que añadirlo a la clase como tal.</p>
<p>Por otro lado, nos permite conservar el principio de <strong>Open/Closed </strong>del patrón de diseño <strong>SOLID</strong> visto en<strong> este post</strong>. En donde cada entidad o clase esta abierta para su extensión pero cerrada para su modificación.</p>
<blockquote>
<p><em>También nos permite mantener nuestras clases con responsabilidades únicas por ende nuestras clases evitan complejidad y se mantienen ligeras de código.</em>
<em>Se acopla también al principio <strong>Single Responsability</strong> de <strong>SOLID</strong></em></p>
</blockquote>
<h2 id="ejemplo-de-implementacion-del-patron-de-diseno-decorator-en-php">Ejemplo de implementación del patrón de diseño DECORATOR en PHP</h2>
<p>Para este ejemplo imaginemos que necesitamos calcular el precio de una Macbook basado en su versión y tamaño de pantalla.</p>
<p>Lo primero seria definir nuestra clase <strong>Macbook</strong> la cual implementa el getter para obtener el precio base del producto.</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Macbook</span>
</span>{
    <span class="hljs-keyword">protected</span> $basePrice = <span class="hljs-number">1500</span>;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getPrice</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;basePrice;
    }
}
</code></pre><p>Lo siguiente es generar nuestra clase abstracta decoradora la cual llamaremos <strong>MacbookDecorator</strong></p>
<pre><code><span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MacbookDecorator</span>
</span>{
    <span class="hljs-keyword">protected</span> $price;
    <span class="hljs-keyword">protected</span> $macbook;
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">$macbook</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;macbook = $macbook;
    }
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getPrice</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;macbook-&gt;getPrice() + <span class="hljs-keyword">$this</span>-&gt;price;
    }
}
</code></pre><p>Como podemos ver, añade una nueva funcionalidad la cual es calcular el precio base de la macbook en donde sumamos el precio base con el precio según la versión y tamaño de la pantalla. Verémos mas adelante como funciona.</p>
<p>Ahora vamos a crear una versión nueva del macbook el cual incrementará el precio de la macbook base. Añadiremos la versión MacbookPro, para ello creamos nuestra clase <strong>MacbookPro</strong> la cual va a extender de nuestro decorador.</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MacbookPro</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">MacbookDecorator</span> 
</span>{ 
  <span class="hljs-keyword">protected</span> $price = <span class="hljs-number">950</span>; 
}
</code></pre><p>De igual forma crearemos dos clases para nuestros tamaños de pantalla disponible.</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WithDisplaySize15</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">MacbookDecorator</span> 
</span>{ 
  <span class="hljs-keyword">protected</span> $price = <span class="hljs-number">350</span>; 
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WithDisplaySize17</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">MacbookDecorator</span> 
</span>{ 
  <span class="hljs-keyword">protected</span> $price = <span class="hljs-number">700</span>; 
}
</code></pre><p>Gracias al decorator podemos combinar nuestras clases para generar variantes de nuestro producto por ejemplo para nuestra tienda de e-commerce.</p>
<h2 id="probando-la-implementacion-anterior">Probando la implementación anterior</h2>
<p>Para probar veamos lo siguiente:</p>
<pre><code>$macbook = <span class="hljs-keyword">new</span> Macbook();
<span class="hljs-keyword">echo</span> <span class="hljs-string">'Una Macbook con pantalla de 13 pulgadas cuesta '</span> . $macbook-&gt;getPrice() . <span class="hljs-string">' euros'</span> . PHP_EOL;

$macbook15Pulg = <span class="hljs-keyword">new</span> WithDisplaySize15(<span class="hljs-keyword">new</span> Macbook());
<span class="hljs-keyword">echo</span> <span class="hljs-string">'Una Macbook con pantalla de 15 pulgadas cuesta '</span> . $macbook15Pulg-&gt;getPrice() . <span class="hljs-string">' euros'</span> . PHP_EOL;

$macbook17Pulg = <span class="hljs-keyword">new</span> WithDisplaySize17(<span class="hljs-keyword">new</span> Macbook());
<span class="hljs-keyword">echo</span> <span class="hljs-string">'Una Macbook con pantalla de 17 pulgadas cuesta '</span> . $macbook17Pulg-&gt;getPrice() . <span class="hljs-string">' euros'</span> . PHP_EOL;

$macbookPro = <span class="hljs-keyword">new</span> MacbookPro(<span class="hljs-keyword">new</span> Macbook());
<span class="hljs-keyword">echo</span> <span class="hljs-string">'Una Macbook Pro con pantalla de 13 pulgadas cuesta '</span> . $macbookPro-&gt;getPrice() . <span class="hljs-string">' euros'</span> . PHP_EOL;

$macbookPro15Pulg = <span class="hljs-keyword">new</span> WithDisplaySize15(<span class="hljs-keyword">new</span> MacbookPro(<span class="hljs-keyword">new</span> Macbook()));
<span class="hljs-keyword">echo</span> <span class="hljs-string">'Una Macbook Pro con pantalla de 15 pulgadas cuesta'</span> . $macbookPro15Pulg-&gt;getPrice() . <span class="hljs-string">' euros'</span> . PHP_EOL;

$macbookPro17Pulg = <span class="hljs-keyword">new</span> WithDisplaySize17(<span class="hljs-keyword">new</span> MacbookPro(<span class="hljs-keyword">new</span> Macbook()));
<span class="hljs-keyword">echo</span> <span class="hljs-string">'Una Macbook Pro con patanlla de 17 pulgadas cuesta '</span> . $macbookPro17Pulg-&gt;getPrice() . <span class="hljs-string">' euros'</span> . PHP_EOL;
</code></pre><p>Con esta implementación, podremos tener el precio de la macbook base ( que viene con 13 pulgadas), la misma versión pero con pantalla de 15 y 17 pulgadas respectivamente.</p>
<p>Lo mismo con la versión MacbookPro. Puedes ver el de este ejemplo en mi <a target="_blank" href="https://gist.github.com/fjugaldev/fda87196efa5d5675bf885ebb03b3ede">**github</a>**</p>
<p>Otra forma de implementar en este patrón de diseño es por ejemplo en nuestros ApplicationServices o UseCases en donde cada uno tiene una funcionalidad específica pero queremos que cuando se ejecuten, se registre un log y se notifique por email sobre la acción realizada.</p>
<p>Aquí el approach seria, crear un decorator para nuestros ApplicationServices en donde inyectemos nuestra clase Logger y nuestra clase Mailer y de cierta forma añadimos funcionalidad extra de una forma simple y sutil, sin sobrecargar nuestras clases y sin repetir funcionalidad.</p>
<p>Hasta aqui todo lo relacionado con este patrón de diseño super útil y que debemos tener en cuenta para nuestros desarrollos.</p>
<p>Todo el contenido del ejemplo puedes conseguirlo en este <a target="_blank" href="https://gist.github.com/fjugaldev/fda87196efa5d5675bf885ebb03b3ede">**gist</a>** de Github.</p>
<p>Recuerda que si tienes alguna sugerencia o pregunta, no dudes en dejar tus comentarios al final del post.</p>
<p>Si te gustó este post, ayúdame a que pueda servirle a muchas más personas, compartiendo mis contenidos en tus redes sociales.</p>
<p>Espero que este post haya sido de gran ayuda para ti, y como siempre, cualquier inquietud o duda que tengas, puedes contactarme por cualquiera de las vías disponibles, o dejando tus comentarios al final de este post. También puedes sugerir que temas o post te gustaría leer a futuro.</p>
]]></content:encoded></item><item><title><![CDATA[Introducción a la Arquitectura Hexagonal]]></title><description><![CDATA[En el episodio 5 de mi podcast de **tecnología estuve hablando brevemente y de forma genérica sobre esta arquitectura y hoy quiero darte una Introducción a la Arquitectura Hexagonal** un poco mas explicita.
Arquitectura de Software
Antes de empezar, ...]]></description><link>https://franciscougalde.com/introduccion-a-la-arquitectura-hexagonal</link><guid isPermaLink="true">https://franciscougalde.com/introduccion-a-la-arquitectura-hexagonal</guid><category><![CDATA[software architecture]]></category><category><![CDATA[clean code]]></category><category><![CDATA[PHP]]></category><category><![CDATA[software development]]></category><category><![CDATA[Programming Tips]]></category><dc:creator><![CDATA[Francisco Ugalde]]></dc:creator><pubDate>Tue, 17 Sep 2019 08:42:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628328888441/I8eOPEOW_.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>En el <a target="_blank" href="https://www.franciscougalde.com/2019/08/09/introduccion-a-la-arquitectura-hexagonal-ep-5-codingrocks/"><strong>episodio 5 de mi podcast</strong> <strong>de</strong> **tecnología</a><strong> estuve hablando brevemente y de forma genérica sobre esta arquitectura y hoy quiero darte una </strong>Introducción a la Arquitectura Hexagonal** un poco mas explicita.</p>
<h2 id="arquitectura-de-software">Arquitectura de Software</h2>
<p>Antes de empezar, es importante saber que la arquitectura de software es un conjunto de convenciones, reglas y normas que se deben cumplir durante el <strong>desarrollo</strong> <strong>de</strong> <strong>software</strong> para garantizar <strong>calidad</strong>, <strong>rendimiento</strong> y <strong>escalabilidad</strong> a lo largo del tiempo.</p>
<p>El implementar una arquitectura de software nos va a permitir entre otras cosas, que todos los involucrados en el proyecto, desarrolladores, analistas, devops, etc. puedan compartir una misma linea de trabajo y de cierta manera ir hacia una misma dirección.</p>
<p>Vale la pena resaltar que la arquitectura de software representa un pilar fundamental en la creación de software y que debe situarse en la parte mas alta del diseño de software.</p>
<p>Una arquitectura de software bien definida nos va a garantizar entre otras cosas, escalabilidad, rendimiento y sobre todo éxito al momento de desarrollar el proyecto.</p>
<p>Algunos ejemplos de arquitecturas que ya muchos de ustedes conocen y utilizan en sus proyectos son el <strong>Modelo Vista Controlador</strong> ( <strong>MVC</strong>), que ya muchos frameworks lo incorporan nativamente. <strong>Arquitectura Orientada a Servicios</strong> ( <strong>SOA</strong> por sus siglas en ingles) o tan sencillo como la arquitectura <strong>Cliente-Servidor</strong>.</p>
<h2 id="arquitectura-hexagonal">Arquitectura Hexagonal</h2>
<p>Dado que la complejidad de los sistemas a desarrollar hoy dia se ha incrementado notablemente, se ha requerido cada vez mas el uso de “ <strong>Arquitecturas Limpias</strong>” o “ <strong>Clean Architecture</strong> “ que nos permitan separar las responsabilidades en capas y por ende la definición de reglas entre ellas.</p>
<p>La arquitectura hexagonal, también conocida como “ <strong>Arquitectura de Puertos y Adaptadores</strong> “ por si gustas leer un poco mas en profundidad.</p>
<p>Se refiere a Puertos y Adaptadores por:</p>
<ul>
<li><p><strong>Puerto</strong>: definición de una interfaz pública.</p>
</li>
<li><p><strong>Adapter</strong>: especialización de un puerto para un contexto concreto. Es decir, una clase que implemente una interfaz o puerto.</p>
</li>
</ul>
<p>Esta arquitectura también se basa precisamente en un conjunto de normas, patrones y reglas, expresadas en capas que se añaden para identificar responsabilidades, definir la forma en que se accede a ellas y el flujo que tendrán a lo largo del proyecto.</p>
<p>Lo interesante de esta arquitectura es que pese a que nos obliga a seguir lineamientos y reglas, es totalmente flexible al momento de ser implementada en nuestros proyectos.</p>
<p>He visto cómo en distintos proyectos su implementación, la estructura de directorios, la identificación de las capas, varia y sin embargo sigue manteniendo y haciendo caso fiel a sus principios.</p>
<h2 id="beneficios-de-la-arquitectura-hexagonal">Beneficios de la Arquitectura Hexagonal</h2>
<ul>
<li><p>Mediante sus reglas, nos guía netamente hacia la construcción de un software de Calidad.</p>
</li>
<li><p>La Arquitectura Hexagonal abraza al patrón <strong>SOLID</strong> por lo que estamos ante una arquitectura que fomenta el uso de patrones de diseño altamente efectivos.</p>
</li>
<li><p>Nos obliga a que el core business o nuestra lógica de negocios no este acoplada a ninguna tecnología o framework.</p>
</li>
<li><p>Facilita estar desacoplado del método de entrega haciendo que sea más sencillo que un caso de uso funcione para una <strong>aplicación móvil</strong>, un <strong>API Rest</strong>, una web tradicional, una web <strong>SPA</strong> por , etc…</p>
</li>
<li><p>Como cualquier arquitectura basada en la inversión de dependencias facilita que los componentes se puedan <em>unit testear</em>.</p>
</li>
</ul>
<h2 id="entendiendo-la-arquitectura-hexagonal">Entendiendo la Arquitectura Hexagonal</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628328885420/Hm7K5lMH9.jpeg" alt /></p>
<p>Ahora bien, muy bonito eso de las capas, de los puertos y adaptadores, de las reglas y principios, pero y de que va todo esto?</p>
<p>Pues bien, en esta Introducción a la <strong>Arquitectura Hexagonal</strong>, quiero mostrarte cuales son esas capas que se añaden, cuál es la función de cada capa y cuál es el flujo entre ellas.</p>
<p>La <strong>arquitectura hexagonal</strong>, como su nombre lo dice, puede ser vista como un simple hexágono, sin importar el numero de lados, es solo a manera representativa.</p>
<p>También, he visto algunos artículos donde explican la arquitectura hexagonal basándose en el diagrama de cebolla.</p>
<p>En este tipo de diagrama, cada capa de la cebolla representa una capa de la arquitectura visualizándolas desde lo mas externo a lo más interno.</p>
<h2 id="capas-de-la-arquitectura-hexagonal">Capas de la Arquitectura Hexagonal</h2>
<ul>
<li><p>Infrastructure</p>
</li>
<li><p>Application</p>
</li>
<li><p>Domain</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628328886812/p_4uCQKna.png" alt /></p>
<p><strong>Infrasctructure</strong>: Corresponde a todo lo que tenga que ver con tecnologías y frameworks, por ejemplo un servicio o adaptador de Email, o un sistema de colas RabbitMQ, los controladores, migraciones de doctrine, los Commands de terminal, entre otros.</p>
<p><strong>Application</strong>: Aquí es donde residen los Casos de Uso ó Application Services que son los encargados de orquestar cada funcionalidad de la aplicación.</p>
<p><strong>Domain</strong>: El domain es el núcleo de esta arquitectura y en esta capa reside todo lo que debemos proteger de nuestro core business.</p>
<p>Por ejemplo, los modelos, objetos de valor, interfaces, validaciones, entre otros.</p>
<p>Por último y no menos importante, es importante conocer el flujo entre ellas, ya que las capas mas externas pueden conocer lo que hay en las capas mas internas, pero una capa interna no conoce lo que se implementa en su capa mas externa.</p>
<p>Esto último cumple con el principio de inversión de dependencias de los principios <a target="_blank" href="https://www.franciscougalde.com/2019/07/26/patrones-de-diseno-en-php-solid/">**SOLID</a><strong>. Si quieres leer un poco más sobre este patrón, puedes ir a [</strong>este<strong> </strong>post](https://www.franciscougalde.com/2019/07/26/patrones-de-diseno-en-php-solid/)**.</p>
<h2 id="consideraciones-finales">Consideraciones finales</h2>
<p>He de decirte estimado lector, que hoy en día, la tecnología avanza a pasos agigantados, y es por ello que debemos mantenernos al pie del cañon con todo este tema de lo contrario quedaremos deprecados.</p>
<p>No obstante es importante que incorporemos arquitectura de software en nuestros proyectos independientemente del framework o tecnología que utilicemos.</p>
<p>Esto para garantizar y proteger nuestro legado más preciado que es el núcleo de la aplicación, para que si el día de mañana la tecnología o framework muere, nuestro desarrollo pueda ser re-implementado nuevamente sin tanto trauma.</p>
<p>A simple vista esto es lo que representa la arquitectura hexagonal. En próximos post trataré de ampliar un poco más la información y de añadir un poco más como por ejemplo: <strong>Domain</strong> <strong>Driven</strong> <strong>Design</strong> ( <strong>DDD</strong>) y como combinarlo con la <strong>arquitectura hexagonal</strong>.</p>
<p>Recuerda que si tienes alguna sugerencia o pregunta, no dudes en dejar tus comentarios al final del post.</p>
<p>Si te gustó este post, ayúdame a que pueda servirle a muchas más personas, compartiendo mis contenidos en tus redes sociales.</p>
<p>Espero que este post haya sido de gran ayuda para ti, y como siempre, cualquier inquietud o duda que tengas, puedes contactarme por cualquiera de las vías disponibles, o dejando tus comentarios al final de este post. También puedes sugerir que temas o post te gustaría leer a futuro.</p>
]]></content:encoded></item><item><title><![CDATA[Introducción a los Microservicios en PHP]]></title><description><![CDATA[Introducción a los Microservicios en PHP
La arquitectura basada en Microservicios en PHP es un concepto que esta muy de moda y que ha sido implementado por muchos gigantes tecnológicos como Amazon, eBay, Netflix Twitter, Paypal entre otros.
En este p...]]></description><link>https://franciscougalde.com/introduccion-a-los-microservicios-en-php</link><guid isPermaLink="true">https://franciscougalde.com/introduccion-a-los-microservicios-en-php</guid><category><![CDATA[Microservices]]></category><category><![CDATA[PHP]]></category><category><![CDATA[distributed system]]></category><category><![CDATA[software architecture]]></category><category><![CDATA[software development]]></category><dc:creator><![CDATA[Francisco Ugalde]]></dc:creator><pubDate>Fri, 13 Sep 2019 07:23:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628841121110/7smzml7O5.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="introduccion-a-los-microservicios-en-php">Introducción a los Microservicios en PHP</h2>
<p>La arquitectura basada en <strong>Microservicios en PHP</strong> es un concepto que esta muy de moda y que ha sido implementado por muchos gigantes tecnológicos como Amazon, eBay, Netflix Twitter, Paypal entre otros.</p>
<p>En este post quiero adentrarte un poco sobre lo que es un <strong>microservicios</strong> en comparación a los sistemas monolíticos, cuales son sus ventajas y desventajas y sobre todo, cuando debemos implementar la arquitectura de <strong>Microservicios en PHP</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628701345292/pMSesJJ9A.jpeg" alt="vnkbqnbwlqbmim3tn1ipiy_rhri.jpeg" />
<strong><em>Microservices, Microservices Everywhere!</em></strong></p>
<h2 id="pero-y-que-son-los-microservicios-en-php">Pero y… ¿Qué son los Microservicios en PHP?</h2>
<p>Generalmente, los grandes y complejos sistemas se han desarrollado siguiendo lo que hasta ahora conocemos como sistemas monolíticos (mono-proceso) donde el mantenimiento, escalabilidad y evolución, se tornaba en algo traumático.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628701231929/ErPPCJPvC.png" alt="TUFDXa_Ju.png" /></p>
<p>Es aquí en donde aparece la arquitectura basada en <strong>microservicios</strong> el cual su principio se basa en identificar y separar funcionalidad del sistema en <strong>micro proyectos </strong>o <strong>servicios</strong> <strong>autónomos</strong> que trabajan de forma independiente.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628701394870/JvNkHuBGUs.jpeg" alt="w01_wta6_.jpeg" /></p>
<p>Es decir, cada micro servicio corresponde por así decirlo a un módulo o bundle cuya funcionalidad es específica. Y que se estará ejecutando de forma paralela en distintos servidores y comunicándose entre ellos por diferentes vías disponibles: <strong>Http</strong> <strong>Request</strong>, <strong>Proyecciones</strong>, <strong>Colas</strong> de <strong>Mensajes</strong>, entre otros.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628701405261/lqawZ9ARA.jpeg" alt="5sP50dNNN.jpeg" /></p>
<p>Cada <strong>microservicio</strong> es responsable de brindar solución a un área de negocio concreta, abstrayendo al resto del sistema de los detalles concretos de la implementación, favoreciendo su <strong>independencia</strong>, el <strong>mantenimiento</strong> y la <strong>evolución</strong> de cada uno de ellos.</p>
<p>Al gestionar cada micro servicio como un pequeño sistema, nos da la posibilidad de ser desplegados sin perjudicar a los demás, favoreciendo así la <strong>escalabilidad</strong>.</p>
<h2 id="cuales-son-sus-ventajas">¿Cuáles son sus ventajas?</h2>
<ul>
<li><p>Potencia la diversidad tecnológica: es decir, podemos utilizar distintos stacks tecnológicos para cada microservicio, incluso, distintos lenguajes de programación.</p>
</li>
<li><p>Permite despliegues independientes.</p>
</li>
<li><p>La capacidad de testing de cada microservicio es mayor.</p>
</li>
<li><p>Permite que los desarrollos sean independientes y puedan avanzar en paralelo.</p>
</li>
<li><p>La escalabilidad se torna mas eficiente y continua.</p>
</li>
<li><p>Facilita el mantenimiento a lo largo del tiempo.</p>
</li>
</ul>
<h2 id="cuales-son-sus-desventajas">¿Cuáles son sus desventajas?</h2>
<p>Las desventajas de los <strong>microservicios</strong> se deben en gran parte a la introducción del concepto de <strong>sistemas</strong> <strong>distribuidos</strong>, algunas de estas son:</p>
<ul>
<li><p>Aumentará la complejidad en la gestión de la configuración y despliegue por lo que cada <strong>microservicio</strong> va a requerir su propia configuración de build, testing, despliegue (Jenkins, CircleCI, Git, etc.).</p>
</li>
<li><p>Aumenta la complejidad para mantener la transaccionalidad de cada operación.</p>
</li>
<li><p>El rendimiento se puede ver afectado debido a saturaciones de la red o a procesos de (de)serialización.</p>
</li>
<li><p>Monitorizar el sistema será más complejo.</p>
</li>
<li><p>Será más difícil gestionar los errores correctamente.</p>
</li>
</ul>
<h2 id="cuando-implementar-la-arquitectura-de-microservicios-en-php">¿Cuándo implementar la arquitectura de Microservicios en PHP?</h2>
<p>La arquitectura de <strong>microservicios</strong> supone un esfuerzo extra a los desarrolladores no solo a nivel de implementación si no a nivel de configuración, comunicación, monitorización, manejo de los errores, registro y log de transacciones, entre otros, ademas de otros factores derivados de los sistemas distribuidos.</p>
<p>Todo esto supone un coste de esfuerzo/tiempo añadido al proyecto que debe ser estimado debidamente antes de tomar la decisión final de si implementar o no esta <strong>arquitectura</strong> de <strong>microservicios</strong>.</p>
<p>La decisión de si utilizar o no este tipo de diseño a la hora de desarrollar nuestro software se fundamenta básicamente en el nivel complejidad que va a alcanzar.</p>
<p>Si el nivel de complejidad del software es bajo, no es aconsejable dedicar esfuerzos en implementar esta arquitectura.</p>
<p>Como mencioné anteriormente la finalidad de esta arquitectura de<strong> microservicios</strong> es tratar de distribuir la complejidad de los sistemas en pequeñas piezas cuya responsabilidad o función sea única.</p>
<p>A partir de cierto nivel de complejidad del sistema, las ventajas que ofrecen los microservicios harán viable el esfuerzo necesario que la productividad del equipo sea mayor.</p>
<h2 id="consideraciones-finales">Consideraciones Finales</h2>
<p>La arquitectura de microservicios viene a resolver importantes retos y problemas relacionados a la complejidad de los sistemas actuales.</p>
<p>Y es que gracias a una buena implementación de los mismos garantizan que sistemas complejos, puedan ser gestionados y administrados de forma eficiente.</p>
<p>Sin embargo, hay que tener pulso y mucho tacto a la hora de decidir si utilizar o no esta arquitectura.</p>
<p>Si tienes dudas en cuanto a si utilizar o no esta arquitectura yo te sugiero que pienses en el siguiente flujo de decisiones:</p>
<ol>
<li><p>Inicies el desarrollo del software como un simple sistema monolítico.</p>
</li>
<li><p>Si la complejidad aumenta con cada versión y sientes que se esta convirtiendo en algo insostenible, puedes proceder a pasar de <strong>monolítico</strong> a <strong>microservicios</strong>.</p>
</li>
</ol>
<p>Lo interesante de la arquitectura de <strong>microservicios</strong> es que es totalmente <strong>flexible</strong> y puede ser usado también como patrón de refactoring.</p>
<p>Ya que permite que un sistema <strong>monolítico</strong> se convierta en multiple <strong>microservicios</strong>.</p>
<h2 id="algunas-referencias">Algunas Referencias</h2>
<p>Puedes leer más al respecto en los siguientes artículos.</p>
<ul>
<li><p><a target="_blank" href="https://www.netsolutions.com/insights/best-enterprise-approaches-to-microservices/">Enterprise Approaches to Microservices: Choose Yours Wisely</a>, <a target="_blank" href="https://www.netsolutions.com/insights/author/siddhartha_bhatia/">SIDDHARTHA BHATIA</a></p>
</li>
<li><p><a target="_blank" href="http://martinfowler.com/articles/microservices.html">Microservices</a>. James Lewis y Martin Fowler.</p>
</li>
<li><p>Sam Newman, «The Principles of Microservices», 2015</p>
</li>
<li><p><a target="_blank" href="http://blog.philipphauer.de/microservices-nutshell-pros-cons/#Benefits_in_General">Microservices in a Nutshell. Pros and Cons.</a> Philipp Hauer.</p>
</li>
</ul>
<p>Recuerda que si tienes alguna sugerencia o pregunta, no dudes en dejar tus comentarios al final del post.</p>
<p>Si te gustó este post, ayúdame a que pueda servirle a muchas más personas, compartiendo mis contenidos en tus redes sociales.</p>
<p>Espero que este post haya sido de gran ayuda para ti, y como siempre, cualquier inquietud o duda que tengas, puedes contactarme por cualquiera de las vías disponibles, o dejando tus comentarios al final de este post. También puedes sugerir que temas o post te gustaría leer a futuro</p>
]]></content:encoded></item><item><title><![CDATA[Symfony: ¿Como usar el componente Mime?]]></title><description><![CDATA[Componente MIME de Symfony

El componente **Mime de Symfony fue introducido en la versión 4.3** y aún esta considerado un feature experimental
Nota a considerar antes de comenzar a usarlo en producción.

Otro de los componentes nuevos creados por Sym...]]></description><link>https://franciscougalde.com/symfony-como-usar-el-componente-mime</link><guid isPermaLink="true">https://franciscougalde.com/symfony-como-usar-el-componente-mime</guid><category><![CDATA[Symfony]]></category><category><![CDATA[PHP]]></category><category><![CDATA[framework]]></category><category><![CDATA[frameworks]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Francisco Ugalde]]></dc:creator><pubDate>Fri, 06 Sep 2019 08:32:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628841156139/ulttJ8_LW.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="componente-mime-de-symfony">Componente MIME de Symfony</h2>
<blockquote>
<p><em>El componente <a target="_blank" href="https://symfony.com/doc/current/components/mime.html">**Mime</a><strong> de </strong>Symfony<strong> fue introducido en la versión </strong>4.3** y aún esta considerado un feature experimental</em>
<em>Nota a considerar antes de comenzar a usarlo en producción.</em></p>
</blockquote>
<p>Otro de los componentes nuevos creados por <strong>Symfony</strong> e incluidos en su versión 4.3 es el componente <strong>MIME</strong>.</p>
<p>Este componente nos permite crear y manipular mensajes <strong>MIME</strong>, que es el formato utilizado para enviar emails.</p>
<p>Por otro lado, incluye algunas utilidades relacionadas con “los tipos MIME”. El <a target="_blank" href="https://en.wikipedia.org/wiki/MIME">estandar MIME completo</a> <em>(Multipurpose Internet Mail Extensions)</em> es una serie de estándares que definen las funcionalidades añadidas con el paso del tiempo a los emails originales basados en texto (como la posibilidad de adjuntar archivos o formatear los contenidos con HTML).</p>
<p>El componente <strong>Mime</strong> abstrae toda esa complejidad por nosotros para proporcionar dos formas de crear mensajes <strong>MIME</strong>. La primera es una API de alto nivel basada en la clase <code>Symfony\Component\Mime\Email</code> y que nos permite de forma fácil y sencilla crear emails con requerimientos básicos y comunes:</p>
<pre><code><span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mime</span>\<span class="hljs-title">Email</span>;

$email = (<span class="hljs-keyword">new</span> Email())
    -&gt;from(<span class="hljs-string">'fabien@symfony.com'</span>)
    -&gt;to(<span class="hljs-string">'foo@example.com'</span>)
    -&gt;subject(<span class="hljs-string">'Important Notification'</span>)
    -&gt;text(<span class="hljs-string">'Lorem ipsum...'</span>)
    -&gt;html(<span class="hljs-string">'&lt;h1&gt;Lorem ipsum&lt;/h1&gt; &lt;p&gt;...&lt;/p&gt;'</span>)
;
</code></pre><p>Como se puede ver en el ejemplo anterior, de una forma sencilla nos permite mediante un objeto de la clase <code>Symfony\Component\Mime\Email</code>, configurar los parámetros de envío a los que estamos acostumbrados normalmente.</p>
<p>La otra forma de crear los mensajes <strong>MIME</strong> es con una <strong>API</strong> de bajo nivel basada en la clase <code>Symfony\Component\Mime\Message</code> y que te brinda el control absoluto sobre todas y cada una de las partes del mensaje.</p>
<p>El siguiente ejemplo que veremos a continuación esta basado en el anterior pero profundizando a un nivel mas bajo la <strong>API</strong> y configurando en detalle las opciones que queremos para el envío:</p>
<pre><code><span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mime</span>\<span class="hljs-title">Header</span>\<span class="hljs-title">Headers</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mime</span>\<span class="hljs-title">Message</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mime</span>\<span class="hljs-title">Part</span>\<span class="hljs-title">Multipart</span>\<span class="hljs-title">AlternativePart</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mime</span>\<span class="hljs-title">Part</span>\<span class="hljs-title">TextPart</span>;

$headers = (<span class="hljs-keyword">new</span> Headers())
    -&gt;addMailboxListHeader(<span class="hljs-string">'From'</span>, [<span class="hljs-string">'fabien@symfony.com'</span>])
    -&gt;addMailboxListHeader(<span class="hljs-string">'To'</span>, [<span class="hljs-string">'foo@example.com'</span>])
    -&gt;addTextHeader(<span class="hljs-string">'Subject'</span>, <span class="hljs-string">'Important Notification'</span>)
;

$textContent = <span class="hljs-keyword">new</span> TextPart(<span class="hljs-string">'Lorem ipsum...'</span>);
$htmlContent = <span class="hljs-keyword">new</span> TextPart(<span class="hljs-string">'&lt;h1&gt;Lorem ipsum&lt;/h1&gt; &lt;p&gt;...&lt;/p&gt;'</span>, <span class="hljs-string">'html'</span>);
$body = <span class="hljs-keyword">new</span> AlternativePart($textContent, $htmlContent);

$email = <span class="hljs-keyword">new</span> Message($headers, $body);
</code></pre><h2 id="funcionalidades-extra-del-componente-mime">Funcionalidades extra del componente MIME:</h2>
<ul>
<li><p>Puedes <a target="_blank" href="https://symfony.com/doc/master/components/mime.html#email-addresses">definir las direcciones de email</a> mediante cadenas de texto y objetos, con o sin nombre, etc.</p>
</li>
<li><p>Soporta la posibilidad de <a target="_blank" href="https://symfony.com/doc/master/components/mime.html#embedding-images">embeber imágenes</a>, que es muy útil al crear mensajes HTML complejos.</p>
</li>
<li><p>Soporta los <a target="_blank" href="https://symfony.com/doc/master/components/mime.html#file-attachments">archivos adjuntos</a> usando tanto archivos físicos como recursos/streams PHP.</p>
</li>
</ul>
<h2 id="integracion-con-twig">Integración con Twig</h2>
<p>Otra de las tantas funcionalidades del componente Mime es su integración total con <a target="_blank" href="https://twig.symfony.com/">Twig</a>.</p>
<p>La clase <code>Symfony\Bridge\Twig\Mime\TemplatedEmail</code> por ejemplo permite renderizar una plantilla Twig para generar los contenidos del email:</p>
<pre><code><span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Bridge</span>\<span class="hljs-title">Twig</span>\<span class="hljs-title">Mime</span>\<span class="hljs-title">TemplatedEmail</span>;

$email = (<span class="hljs-keyword">new</span> TemplatedEmail())
    -&gt;from(<span class="hljs-string">'fabien@symfony.com'</span>)
    -&gt;to(<span class="hljs-string">'foo@example.com'</span>)
    <span class="hljs-comment">// ...</span>

    <span class="hljs-comment">// pasa la ruta donde está la plantilla con los contenidos</span>
    -&gt;htmlTemplate(<span class="hljs-string">'messages/user/signup.html.twig'</span>)

    <span class="hljs-comment">// este método define los parámetros (nombre =&gt; valor) pasados a la plantilla</span>
    -&gt;context([
        <span class="hljs-string">'expiration_date'</span> =&gt; <span class="hljs-keyword">new</span> \DateTime(<span class="hljs-string">'+7 days'</span>),
        <span class="hljs-string">'username'</span> =&gt; <span class="hljs-string">'foo'</span>,
    ])
;
</code></pre><h2 id="funcionalidades-extras-del-componente-mime-con-twig">Funcionalidades extras del componente MIME con TWIG</h2>
<ul>
<li><p><a target="_blank" href="https://symfony.com/doc/master/components/mime.html#embedding-images-in-emails-with-twig">Permite adjuntar de forma más sencilla</a> las imágenes.</p>
</li>
<li><p><a target="_blank" href="https://symfony.com/doc/master/components/mime.html#inlining-css-styles-in-emails-with-twig">Creación automática de estilos CSS inline</a>: esto es super importante puesto que no todos los clientes de email soportan estilos CSS embebidos entre las etiquetas <code>&amp;lt;style&amp;gt; ... &amp;lt;/style&amp;gt;</code>.</p>
</li>
<li><p>Permite el <a target="_blank" href="https://symfony.com/doc/master/components/mime.html#rendering-markdown-contents-in-emails-with-twig">Renderizado de contenidos Markdown</a> si quieres definir el contenido de tus emails con este popular formato.</p>
</li>
<li><p><a target="_blank" href="https://symfony.com/doc/master/components/mime.html#using-the-inky-email-templating-language-with-twig">Soporte del lenguaje de plantillas Inky</a>, que es uno de los más populares para crear mensajes HTML con diseño <em>responsive</em>.</p>
</li>
</ul>
<p>El <a target="_blank" href="https://symfony.com/components/Mime">componente Mime</a> definitivamente es tan completo que te provee de absolutamente todo lo que necesitas para crear cualquier email que requieras para tus desarrollos</p>
<p>Lo que sí tienes que tener en cuenta es que no envía los emails. El envío de los mensajes esta delegado a otro de los componentes de Symfony llamado “” y que se incluye también desde la versión <strong>4.3</strong> de <strong>Symfony</strong>. Estaré publicando acerca de este componente más adelante.</p>
<h2 id="serializando-mensajes-de-email">Serializando Mensajes de Email</h2>
<p>Los mensajes de email creados con las clases de Email o Message, pueden ser fácilmente serializadas puesto que ellas son objetos simple de datos.</p>
<pre><code>$email = (<span class="hljs-keyword">new</span> Email())
    -&gt;from(<span class="hljs-string">'fabien@symfony.com'</span>)
    <span class="hljs-comment">// ...</span>
;

$serializedEmail = serialize($email);
</code></pre><p>Un caso de uso particular es para almacenar los mensajes de email serializados, incluirlos luego en un Message y ser enviado con el<a target="_blank" href="https://www.franciscougalde.com/2019/07/17/symfony-como-usar-el-componente-messenger-parte-1/"> Componente Messenger</a> y ser recreado luego nuevamente cuando se vaya a enviar.</p>
<p>Debes usar la clase RawMessage para recrear el mensaje de email desde nuestros contenidos serializados:</p>
<pre><code><span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mime</span>\<span class="hljs-title">RawMessage</span>;

<span class="hljs-comment">// ...</span>
$serializedEmail = serialize($email);

<span class="hljs-comment">// later, recreate the original message to actually send it</span>
$message = <span class="hljs-keyword">new</span> RawMessage(unserialize($serializedEmail));
</code></pre><p>Es todo por ahora con todo lo relacionado con este maravilloso componente de <strong>Symfony</strong>. Estaré publicando actualizaciones a medida que el componente vaya incorporando nuevas funcionalidades.</p>
<p>Recuerda que si tienes alguna sugerencia o pregunta, no dudes en dejar tus comentarios al final del post.</p>
<p>Si te gustó este post, ayúdame a que pueda servirle a muchas más personas, compartiendo mis contenidos en tus redes sociales.</p>
<p>Espero que este post haya sido de gran ayuda para ti, y como siempre, cualquier inquietud o duda que tengas, puedes contactarme por cualquiera de las vías disponibles, o dejando tus comentarios al final de este post. También puedes sugerir que temas o post te gustaría leer a futuro.</p>
]]></content:encoded></item><item><title><![CDATA[Slim Framework: Una breve introducción]]></title><description><![CDATA[Slim en principio es un micro framework cuya función principal es ayudarte a escribir simples, pero poderosas aplicaciones y API’s.

En su núcleo, Slim es un despachador que recibe una petición HTTP, invoca un rutina callback, y devuelve una respuest...]]></description><link>https://franciscougalde.com/slim-framework-una-breve-introduccion</link><guid isPermaLink="true">https://franciscougalde.com/slim-framework-una-breve-introduccion</guid><category><![CDATA[PHP]]></category><category><![CDATA[framework]]></category><category><![CDATA[frameworks]]></category><category><![CDATA[oop]]></category><category><![CDATA[programing]]></category><dc:creator><![CDATA[Francisco Ugalde]]></dc:creator><pubDate>Tue, 27 Aug 2019 17:35:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628328994917/Y54pen7C-.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Slim en principio es un micro framework cuya función principal es ayudarte a escribir simples, pero poderosas aplicaciones y API’s.</p>
<blockquote>
<p><em>En su núcleo, <strong>Slim</strong> es un despachador que recibe una petición <strong>HTTP</strong>, invoca un rutina <strong>callback</strong>, y devuelve una respuesta <strong>HTTP</strong></em>
<em>Así de sencillo!</em></p>
</blockquote>
<h2 id="cuando-usar-slim">Cuando usar Slim?</h2>
<p><strong>Slim</strong> <strong>Framework</strong> es una herramienta ideal para crear <strong>API</strong>´ <strong>s</strong> que <strong>consuman</strong>, <strong>reutilicen</strong> o <strong>publiquen</strong> datos.</p>
<p>También es recomendada cuándo requieras hacer un prototyping de una aplicación en poco tiempo, es decir, cuando necesites poner en marcha un proyecto lo antes posible.</p>
<p>Es que, incluso puedes crear aplicaciones web que incluyan interfaces de usuario. Sinceramente este framework es potente y lo interesante de todo es que es rápido y muy ligero de código.</p>
<p>Otro punto a favor es que su curva de aprendizaje es muy corta por lo que de seguro te podrás adentrar en él en pocos días, e incluso hasta en una misma tarde.</p>
<h2 id="como-funciona">Cómo funciona?</h2>
<p>Lo primero que necesitamos es un servidor web como <strong>Nginx</strong> o <strong>Apache</strong>. Para ello, te sugiero leer el siguiente .</p>
<p>Debes configurar tu servidor web de tal forma que envíe todas las peticiones apropiadas a un archivo <strong>PHP</strong> que actúa de “ <strong>controlador frontal</strong>” ó “ <strong>front-controller</strong> “.</p>
<p>Desde este fichero <strong>PHP</strong> es que iniciamos y ejecutamos nuestra app con <strong>Slim Framework</strong></p>
<p>Una aplicación <strong>Slim</strong> contiene rutas que responden a una petición <strong>HTTP</strong> específica. Cada ruta invoca un “ <strong>callback</strong>” que no es más que un método que se ejecuta y retorna una respuesta <strong>HTTP</strong>.</p>
<p>Para comenzar, lo primero que hay que hacer es instanciar y configurar la aplicación <strong>Slim</strong>. Luego, definir las rutas de la aplicación y finalmente ejecutar la aplicación <strong>Slim</strong>.</p>
<p>Un ejemplo de como quedaría nuestro controlador frontal sería:</p>
<pre><code><span class="hljs-meta">&lt;?php</span>
<span class="hljs-keyword">use</span> <span class="hljs-title">Psr</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Message</span>\<span class="hljs-title">ResponseInterface</span> <span class="hljs-title">as</span> <span class="hljs-title">Response</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Psr</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Message</span>\<span class="hljs-title">ServerRequestInterface</span> <span class="hljs-title">as</span> <span class="hljs-title">Request</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Slim</span>\<span class="hljs-title">Factory</span>\<span class="hljs-title">AppFactory</span>;

<span class="hljs-keyword">require</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">'/../vendor/autoload.php'</span>;

<span class="hljs-comment">/**
 * Instantiate App
 *
 * In order for the factory to work you need to ensure you have installed
 * a supported PSR-7 implementation of your choice e.g.: Slim PSR-7 and a supported
 * ServerRequest creator (included with Slim PSR-7)
 */</span>
$app = AppFactory::create();

<span class="hljs-comment">// Add Routing Middleware</span>
$app-&gt;addRoutingMiddleware();

<span class="hljs-comment">/*
 * Add Error Handling Middleware
 *
 * <span class="hljs-doctag">@param</span> bool $displayErrorDetails -&gt; Should be set to false in production
 * <span class="hljs-doctag">@param</span> bool $logErrors -&gt; Parameter is passed to the default ErrorHandler
 * <span class="hljs-doctag">@param</span> bool $logErrorDetails -&gt; Display error details in error log
 * which can be replaced by a callable of your choice.

 * <span class="hljs-doctag">Note:</span> This middleware should be added last. It will not handle any exceptions/errors
 * for middleware added after it.
 */</span>
$errorMiddleware = $app-&gt;addErrorMiddleware(<span class="hljs-literal">true</span>, <span class="hljs-literal">true</span>, <span class="hljs-literal">true</span>);

<span class="hljs-comment">// Define app routes</span>
$app-&gt;get(<span class="hljs-string">'/hello/{name}'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Request $request, Response $response, $args</span>) </span>{
    $name = $args[<span class="hljs-string">'name'</span>];
    $response-&gt;getBody()-&gt;write(<span class="hljs-string">"Hello, <span class="hljs-subst">$name</span>"</span>);
    <span class="hljs-keyword">return</span> $response;
});

<span class="hljs-comment">// Run app</span>
$app-&gt;run();
</code></pre><h2 id="request-y-response">Request y Response</h2>
<p>Cuando creamos una aplicación <strong>Slim</strong>, a menudo estaremos trabajando directamente con los objetos <strong>Request </strong>y <strong>Response</strong>. Estos objetos representan la solicitud HTTP real recibida por el servidor web y la eventual respuesta HTTP devuelta al cliente.</p>
<p>Cada ruta de la aplicación <strong>Slim</strong> recibe los objetos de <strong>Request</strong> y <strong>Response</strong> actuales como argumentos del <strong>callback</strong>. Es decir, nuestro método invocado cuando se recibe un request, tendrá como argumentos el <strong>Request</strong> y <strong>Response</strong> de la petición actual.</p>
<p>Estos objetos implementan las populares interfaces <strong>PSR-7</strong>. La ruta de la aplicación <strong>Slim</strong> puede inspeccionar o manipular estos objetos según sea necesario. En definitiva, cada ruta de aplicación Slim <strong>DEBE </strong>devolver un objeto de respuesta PSR-7.</p>
<p>Muy bien, y como empiezo a usar <strong>Slim framework</strong>?</p>
<h2 id="instalacion-de-slim-framework">Instalación de Slim Framework</h2>
<h2 id="requerimientos-del-sistema">Requerimientos del Sistema</h2>
<ul>
<li><p>Servidor Web con reescritura de URL</p>
</li>
<li><p>PHP 7.1 ó superior</p>
</li>
</ul>
<h2 id="paso-1-instalar-composer">Paso 1: Instalar Composer</h2>
<p>No tienes instalado <strong>Composer</strong>? Es sencillo de instalar, puedes ir a <a target="_blank" href="https://getcomposer.org/download/">**pagina de descarga</a>** de su web y seguir las instrucciones de instalación.</p>
<h2 id="paso-2-instalar-slim-framework">Paso 2: Instalar Slim Framework</h2>
<p>Se recomienda instalar <strong>Slim Framework</strong> usando .</p>
<p>Sitúate en el directorio raíz del proyecto y ejecuta el siguiente comando:</p>
<pre><code><span class="hljs-attribute">composer</span> require slim/slim:<span class="hljs-number">4</span>.<span class="hljs-number">0</span>.<span class="hljs-number">0</span>
</code></pre><p>Este comando descarga Slim Framework y todas sus dependencias de terceros en la carpeta <strong>vendor</strong> de tu directorio raíz del proyecto.</p>
<h2 id="paso-3-instalar-una-implementacion-de-psr-7-y-serverrequest-creator">Paso 3: Instalar una implementación de PSR-7 y ServerRequest Creator</h2>
<p>Antes de ponerte en marcha con <strong>Slim Framework</strong> necesitas elegir una implementación PSR-7 que se adapte mejor a los requerimientos y necesidades de tu aplicación.</p>
<p>Para que la detección automática funcione y te permita usar <strong>AppFactory::create(…)</strong> y <strong>App::run(…)</strong> sin tener que crear manualmente un <strong>ServerRequest</strong>, es necesario instalar una de las siguientes implementaciones:</p>
<h3 id="slim-psr-7httpsgithubcomslimphpslim-psr7"><a target="_blank" href="https://github.com/slimphp/Slim-Psr7">Slim PSR-7</a></h3>
<pre><code>composer <span class="hljs-keyword">require</span> slim/psr7
</code></pre><h3 id="nyholm-psr-7httpsgithubcomnyholmpsr7-y-nyholm-psr-7-serverhttpsgithubcomnyholmpsr7-server"><a target="_blank" href="https://github.com/Nyholm/psr7">Nyholm PSR-7</a> y <a target="_blank" href="https://github.com/Nyholm/psr7-server">Nyholm PSR-7 Server</a></h3>
<pre><code><span class="hljs-attribute">composer</span> require nyholm/psr<span class="hljs-number">7</span> nyholm/psr<span class="hljs-number">7</span>-server
</code></pre><h3 id="guzzle-psr-7httpsgithubcomguzzlepsr7-y-guzzle-http-factoryhttpsgithubcomhttp-interophttp-factory-guzzle"><a target="_blank" href="https://github.com/guzzle/psr7">Guzzle PSR-7</a> y <a target="_blank" href="https://github.com/http-interop/http-factory-guzzle">Guzzle HTTP Factory</a></h3>
<pre><code>composer <span class="hljs-keyword">require</span> guzzlehttp/psr7 http-interop/http-factory-guzzle
</code></pre><h3 id="zend-diactoroshttpsgithubcomzendframeworkzend-diactoros"><a target="_blank" href="https://github.com/zendframework/zend-diactoros">Zend Diactoros</a></h3>
<pre><code>composer <span class="hljs-keyword">require</span> zendframework/zend-diactoros
</code></pre><h2 id="paso-4-hello-world">Paso 4: ¡Hello World!</h2>
<pre><code><span class="hljs-meta">&lt;?php</span>
<span class="hljs-keyword">use</span> <span class="hljs-title">Psr</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Message</span>\<span class="hljs-title">ResponseInterface</span> <span class="hljs-title">as</span> <span class="hljs-title">Response</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Psr</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Message</span>\<span class="hljs-title">ServerRequestInterface</span> <span class="hljs-title">as</span> <span class="hljs-title">Request</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Slim</span>\<span class="hljs-title">Factory</span>\<span class="hljs-title">AppFactory</span>;

<span class="hljs-keyword">require</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">'/../vendor/autoload.php'</span>;

$app = AppFactory::create();

$app-&gt;get(<span class="hljs-string">'/'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Request $request, Response $response, $args</span>) </span>{
    $response-&gt;getBody()-&gt;write(<span class="hljs-string">"Hello world!"</span>);
    <span class="hljs-keyword">return</span> $response;
});

$app-&gt;run();
</code></pre><p>Y con esto, ya tienes todo lo necesario para empezar a construir aplicaciones usando <strong>Slim Framework</strong>.</p>
<p>Recuerda que si tienes alguna sugerencia o pregunta, no dudes en dejar tus comentarios al final del post.</p>
<p>Si te gustó este post, ayúdame a que pueda servirle a muchas más personas, compartiendo mis contenidos en tus redes sociales.</p>
<p>Espero que este post haya sido de gran ayuda para ti, y como siempre, cualquier inquietud o duda que tengas, puedes contactarme por cualquiera de las vías disponibles, o dejando tus comentarios al final de este post. También puedes sugerir que temas o post te gustaría leer a futuro.</p>
]]></content:encoded></item><item><title><![CDATA[11 Herramientas para ser más productivos — Ep. 7 #CodingRocks]]></title><description><![CDATA[Quiero que conozcas 11 herramientas para ser mas productivos tanto en el trabajo como en la vida personal
En este episodio quiero compartir contigo algunas herramientas que utilizo día a día para aumentar mi productividad.
Quizás algunas ya las conoz...]]></description><link>https://franciscougalde.com/11-herramientas-para-ser-mas-productivos-ep-7-codingrocks</link><guid isPermaLink="true">https://franciscougalde.com/11-herramientas-para-ser-mas-productivos-ep-7-codingrocks</guid><category><![CDATA[podcast]]></category><category><![CDATA[technology]]></category><category><![CDATA[programming languages]]></category><category><![CDATA[software architecture]]></category><category><![CDATA[PHP]]></category><dc:creator><![CDATA[Francisco Ugalde]]></dc:creator><pubDate>Sun, 25 Aug 2019 20:27:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628328904001/EveGcQ-Zs.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="quiero-que-conozcas-11-herramientas-para-ser-mas-productivos-tanto-en-el-trabajo-como-en-la-vida-personal">Quiero que conozcas 11 herramientas para ser mas productivos tanto en el trabajo como en la vida personal</h2>
<p>En este episodio quiero compartir contigo algunas herramientas que utilizo día a día para aumentar mi productividad.</p>
<p>Quizás algunas ya las conozcas pero para mí es un honor presentarte las que utilizo tanto en proyectos de trabajo como algunas otras para mi vida y planificación personal.</p>
<p>Acompáñame a escuchar este nuevo episodio y conocer un poco más sobre este interesante tema.</p>
<h2 id="lista-de-las-11-herramientas-para-ser-mas-productivos">Lista de las 11 Herramientas para ser más productivos.</h2>
<h2 id="gestion-de-proyectos">Gestión de Proyectos.</h2>
<ul>
<li><p><a target="_blank" href="https://trello.com/">Trello</a></p>
</li>
<li><p><a target="_blank" href="https://app.asana.com/">Asana</a></p>
</li>
</ul>
<h2 id="meetings-o-comunicacion">Meetings ó Comunicación</h2>
<ul>
<li><p><a target="_blank" href="https://whereby.com/">Whereby.com</a> (Antes appear.in)</p>
</li>
<li><p><a target="_blank" href="https://jitsi.org/">Jitsi</a></p>
</li>
</ul>
<h2 id="creacion-de-diagramas">Creación de Diagramas</h2>
<ul>
<li><p><a target="_blank" href="https://www.draw.io/">Draw.io</a></p>
</li>
<li><p><a target="_blank" href="https://www.canva.com/">Canva</a></p>
</li>
</ul>
<h2 id="gestion-de-tiempos">Gestión de Tiempos</h2>
<ul>
<li><p><a target="_blank" href="https://clockify.me/">Clockify</a></p>
</li>
<li><p><a target="_blank" href="https://pomodoro-tracker.com/?lang=es">Pomodoro Tracker</a></p>
</li>
<li><p><a target="_blank" href="https://www.forestapp.cc/">Forest</a></p>
</li>
</ul>
<h2 id="aplicaciones-para-notas">Aplicaciones para Notas</h2>
<ul>
<li><a target="_blank" href="https://kapeli.com/dash">Dash</a></li>
</ul>
<p>Recuerda que si tienes alguna sugerencia o pregunta, no dudes en dejar tus comentarios al final del post.</p>
<p>Si te gustó este post, ayúdame a que pueda servirle a muchas más personas, compartiendo mis contenidos en tus redes sociales.</p>
<p>Espero que este post haya sido de gran ayuda para ti, y como siempre, cualquier inquietud o duda que tengas, puedes contactarme por cualquiera de las vías disponibles, o dejando tus comentarios al final de este post. También puedes sugerir que temas o post te gustaría leer a futuro.</p>
]]></content:encoded></item><item><title><![CDATA[Patrón de diseño FACADE en PHP]]></title><description><![CDATA[El patrón FACADE o Fachada
El objetivo principal del patrón de diseño FACADE en PHP es el de simplificar nuestro sistema gracias a que permite exponer una interfaz mas amigable y fácil de digerir sin necesidad de conocer a fondo cada uno de los sub s...]]></description><link>https://franciscougalde.com/patron-de-diseno-facade-en-php</link><guid isPermaLink="true">https://franciscougalde.com/patron-de-diseno-facade-en-php</guid><category><![CDATA[design patterns]]></category><category><![CDATA[PHP]]></category><category><![CDATA[clean code]]></category><category><![CDATA[software development]]></category><category><![CDATA[software architecture]]></category><dc:creator><![CDATA[Francisco Ugalde]]></dc:creator><pubDate>Wed, 21 Aug 2019 14:49:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628841190699/ujFXBrSrh.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="el-patron-facade-o-fachada">El patrón FACADE o Fachada</h2>
<p>El objetivo principal del patrón de diseño <strong>FACADE</strong> en <strong>PHP</strong> es el de simplificar nuestro sistema gracias a que permite exponer una interfaz mas amigable y fácil de digerir sin necesidad de conocer a fondo cada uno de los sub sistemas que se agrupan en esta “fachada”.</p>
<p>Para tratar de entender mejor el concepto, veamos un diagrama para visualizar mejor el patrón <strong>FACADE</strong>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628328908196/K-A-D4vU6.png" alt /></p>
<p>Aquí podemos ver que tenemos 3 subsistemas el cual son la clase Twitter, Instagram y Facebook, el cual cuya funcionalidad puede ser agrupada en la clase FACADE que hemos llamado: <strong>SocialNetworksClass</strong> quien posteriormente sera utilizada por cualquier clase de servicio.</p>
<p>Continuando con lo presentado en el diagrama, te muestro un ejemplo de código:</p>
<h2 id="ejemplo-de-implementacion-del-patron-de-diseno-facade-en-php">Ejemplo de implementación del Patrón de diseño FACADE en PHP</h2>
<pre><code><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">SocialNetworksInterface</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">publish</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">follow</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">unfollow</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addLike</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">retweet</span>(<span class="hljs-params"></span>)</span>;
}

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">TwitterAPIClientInterface</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">tweet</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">follow</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">unfollow</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addLike</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">retweet</span>(<span class="hljs-params"></span>)</span>;
}

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">InstagramAPIClientInterface</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">publish</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">follow</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">unfollow</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addLike</span>(<span class="hljs-params"></span>)</span>;
}

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">FacebookAPIClientInterface</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addPost</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addLike</span>(<span class="hljs-params"></span>)</span>;
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SocialNetworks</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">SocialNetworksInterface</span>
</span>{
    <span class="hljs-comment">/**
     * <span class="hljs-doctag">@var</span> TwitterAPIClientInterface
     */</span>
    <span class="hljs-keyword">protected</span> $twitterApiClient;

    <span class="hljs-comment">/**
     * <span class="hljs-doctag">@var</span> InstagramAPIClient
     */</span>
    <span class="hljs-keyword">protected</span> $instagramApiClient;

    <span class="hljs-comment">/**
     * <span class="hljs-doctag">@var</span> FacebookAPIClient
     */</span>
    <span class="hljs-keyword">protected</span> $facebookApiClient;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
        TwitterAPIClientInterface $twitterApiClient,
        InstagramAPIClientInterface $instagramApiClient,
        FacebookAPIClientInterface $facebookApiClient
    </span>) </span>{
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">publish</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;twitterApiClient-&gt;tweet();
        <span class="hljs-keyword">$this</span>-&gt;instagramApiClient-&gt;publish();
        <span class="hljs-keyword">$this</span>-&gt;facebookApiClient-&gt;addPost();
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">follow</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;twitterApiClient-&gt;follow();
        <span class="hljs-keyword">$this</span>-&gt;instagramApiClient-&gt;follow();
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">unfollow</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;twitterApiClient-&gt;unfollow();
        <span class="hljs-keyword">$this</span>-&gt;instagramApiClient-&gt;unfollow());
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addLike</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;twitterApiClient-&gt;addLike();
        <span class="hljs-keyword">$this</span>-&gt;instagramApiClient-&gt;addLike();
        <span class="hljs-keyword">$this</span>-&gt;facebookApiClient-&gt;addLike();
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">retweet</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;twitterApiClient-&gt;retweet();
    }

}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TwitterAPIClient</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">TwitterAPIClientInterface</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">tweet</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-comment">// tweet() method implementation</span>
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">follow</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-comment">// follow() method implementation</span>
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">unfollow</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-comment">// unfollow() method implementation</span>
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addLike</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-comment">// addLike() method implementation</span>
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">retweet</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-comment">// retweet() method implementation</span>
    }

}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">InstagramAPIClient</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">InstagramAPIClientInterface</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">publish</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-comment">// publich() method implementation</span>
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">follow</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-comment">// follow() method implementation</span>
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">unfollow</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-comment">// unfollow() method implementation</span>
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addLike</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-comment">// addLike() method implementation</span>
    }

}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FacebookAPIClient</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">FacebookAPIClientInterface</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addPost</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-comment">// addPost() method implementation</span>
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addLike</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-comment">// addLike() method implementation</span>
    }
}
</code></pre><p>El ejemplo que expongo es a manera ilustrativa de cómo implementar el patrón de diseño <strong>FACADE</strong> en tus proyectos.</p>
<p>En el ejemplo expuesto se puede apreciar como toda la funcionalidad de tres sub sistemas, Twitter, Facebook e Instagram, quedan envueltas en una clase <strong>FACHADA</strong> o <strong>FACADE</strong>.</p>
<p>Esto permite simplificar radicalmente la implementación de uno o varios sub sistemas en clases de servicios o en cualquier otro punto donde sea requerido.</p>
<p>Ademas que la clase que implementa nuestra clase <strong>FACADE</strong> no necesita saber internamente cómo funciona cada sub sistema.</p>
<p>Recuerda que si tienes alguna sugerencia o pregunta, no dudes en dejar tus comentarios al final del post.</p>
<p>Si te gustó este post, ayúdame a que pueda servirle a muchas más personas, compartiendo mis contenidos en tus redes sociales.</p>
<p>Espero que este post haya sido de gran ayuda para ti, y como siempre, cualquier inquietud o duda que tengas, puedes contactarme por cualquiera de las vías disponibles, o dejando tus comentarios al final de este post.</p>
<p>También puedes sugerir que temas o post te gustaría leer a futuro.</p>
]]></content:encoded></item><item><title><![CDATA[Costo por Tecnología vs Costo por Conocimiento — Ep. 6 #CodingRocks]]></title><description><![CDATA[¿En la actualidad como estableces el costo de tu trabajo?
En este episodio titulado “ Costo por Tecnología vs Costo por Conocimiento “ quiero debatir un poco sobre el costo y valor de tu trabajo, es decir, el costo en base a la tecnología y el valor ...]]></description><link>https://franciscougalde.com/costo-por-tecnologia-vs-costo-por-conocimiento-ep-6-codingrocks</link><guid isPermaLink="true">https://franciscougalde.com/costo-por-tecnologia-vs-costo-por-conocimiento-ep-6-codingrocks</guid><category><![CDATA[podcast]]></category><category><![CDATA[technology]]></category><category><![CDATA[programming languages]]></category><category><![CDATA[software architecture]]></category><category><![CDATA[software development]]></category><dc:creator><![CDATA[Francisco Ugalde]]></dc:creator><pubDate>Fri, 16 Aug 2019 15:09:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628328914156/94WriI5Ud.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="en-la-actualidad-como-estableces-el-costo-de-tu-trabajo">¿En la actualidad como estableces el costo de tu trabajo?</h2>
<p>En este episodio titulado “ <strong>Costo por Tecnología vs Costo por Conocimiento</strong> “ quiero debatir un poco sobre el costo y valor de tu trabajo, es decir, el costo en base a la tecnología y el valor del conocimiento aplicado, dos factores importantes a la hora de ponerle precio a tu trabajo como desarrollador.</p>
<p>Doy mi punto de vista particular, es algo que opino sobre este tema que es super importante y que entre todos debemos poco a poco empujar para hacer que las empresas reflexionen sobre el valor y el costo de nuestro trabajo.</p>
<p>Acompáñame a escuchar este nuevo episodio y conocer un poco más sobre este interesante tema.</p>
<p>Recuerda que si tienes alguna sugerencia o pregunta, no dudes en dejar tus comentarios al final del post.</p>
<p>Si te gustó este post, ayúdame a que pueda servirle a muchas más personas, compartiendo mis contenidos en tus redes sociales.</p>
<p>Espero que este post haya sido de gran ayuda para ti, y como siempre, cualquier inquietud o duda que tengas, puedes contactarme por cualquiera de las vías disponibles, o dejando tus comentarios al final de este post. También puedes sugerir que temas o post te gustaría leer a futuro.</p>
]]></content:encoded></item><item><title><![CDATA[PHP 7.4: Conoce lo nuevo que traerá]]></title><description><![CDATA[Como es de saber, esta nueva versión será liberada el 28 de Noviembre de 2019. Conoce lo nuevo de PHP 7.4 y empieza a tomar ventaja de sus novedades.
Puede ver la lista completa de funciones y novedades en la **página oficial de RFC.**

Aún cuando PH...]]></description><link>https://franciscougalde.com/php-7-4-conoce-lo-nuevo-que-traera</link><guid isPermaLink="true">https://franciscougalde.com/php-7-4-conoce-lo-nuevo-que-traera</guid><category><![CDATA[PHP]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[software development]]></category><category><![CDATA[PHP7]]></category><category><![CDATA[Programming Tips]]></category><dc:creator><![CDATA[Francisco Ugalde]]></dc:creator><pubDate>Wed, 14 Aug 2019 15:05:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628841218266/twUm0ex--f.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Como es de saber, esta nueva versión será liberada el <strong><em>28 de Noviembre de 2019</em></strong>. Conoce lo nuevo de <strong>PHP 7.4</strong> y empieza a tomar ventaja de sus novedades.</p>
<p>Puede ver la lista completa de funciones y novedades en la <a target="_blank" href="https://wiki.php.net/rfc#php_74">**página oficial de RFC.</a>**</p>
<blockquote>
<p><em>Aún cuando <strong>PHP 7.4</strong> aumenta de forma notable el desempeño y mejora la forma en leer y entender el código, <strong>PHP 8</strong> será la versión con más logros importantes en cuanto a rendimiento de PHP se refiere, ya que la propuesta para la <a target="_blank" href="https://wiki.php.net/rfc/jit">**inclusión de JIT</a>** ya ha sido aprobada actualmente.</em>
<em>A tomar en cuenta…</em></p>
</blockquote>
<p>Y para no extendernos mucho e ir al grano, haré un resumen sencillo de lo nuevo que trae esta versión <strong>7.4</strong> de <strong>PHP</strong>.</p>
<h2 id="arrow-functions-en-php-74">Arrow Functions en PHP 7.4</h2>
<p>Esta actualización ha sido añadida a mi lista de favoritas para esta versión. ?</p>
<p>Arrow functions, también llamadas “ <strong>short closures</strong> “, permiten definir funciones one-liner menos verbosas.</p>
<p>Anteriormente hacíamos cosas como:</p>
<pre><code>array_map(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">User $user</span>) </span>{ 
    <span class="hljs-keyword">return</span> $user-&gt;id; 
}, $users)
</code></pre><p>Ahora, podrás definir lo anterior como:</p>
<pre><code>array_map(fn (User <span class="hljs-variable">$user</span>) =&gt; <span class="hljs-variable">$user</span>-&gt;id, <span class="hljs-variable">$users</span>)
</code></pre><p>Una sintaxis un poco parecida a como se hace en typescript :).</p>
<p>Adicionalmente, hay algunas notas acerca de los Arrow Functions:</p>
<ul>
<li><p>Ellas pueden acceder al ámbito principal sin necesidad de utilizar la palabra clave “<strong>use</strong>”.</p>
</li>
<li><p><code>$this</code> esta disponible como un closure normal.</p>
</li>
<li><p>Pueden contender solo una linea, que también es la linea de retorno.</p>
</li>
</ul>
<h2 id="typed-properties-en-php-74">Typed Properties en PHP 7.4</h2>
<p>Una de mis favoritas, algo que deseaba tener desde hace tiempo. ?</p>
<p>Ahora las propiedades pueden ser tipadas al igual que como ya se implementó con los argumentos de los métodos y funciones.</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span>
</span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> $id;

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">string</span> $name;

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> $age;

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">float</span> $salary;
}
</code></pre><h2 id="consideraciones-adicionales">Consideraciones adicionales</h2>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span>
</span>{
    <span class="hljs-keyword">private</span> ?<span class="hljs-keyword">string</span> $address = <span class="hljs-literal">null</span>;
}
</code></pre><h3 id="listado-de-tipados-disponibles">Listado de tipados disponibles:</h3>
<ul>
<li><p>bool</p>
</li>
<li><p>int</p>
</li>
<li><p>float</p>
</li>
<li><p>string</p>
</li>
<li><p>array</p>
</li>
<li><p>iterable</p>
</li>
<li><p>object</p>
</li>
<li><p>? (nullable)</p>
</li>
<li><p>self &amp; parent</p>
</li>
<li><p>Classes &amp; interfaces</p>
</li>
</ul>
<h2 id="improved-type-variance-en-php-74">Improved type variance en PHP 7.4</h2>
<p>Esta es otra de mis favoritas!!!</p>
<p>Type variance propone poder usar tipos de retornos covariantes y argumentos contra variantes.</p>
<p>Esto significa que podremos definir el tipo de retorno de un método pero al ser implementado o sobre escrito por una clase, podemos variar el tipo de retorno. O en el caso de los argumentos de un método, podemos igualmente variarlo. Veamos un ejemplo:</p>
<h2 id="covariacion-de-tipos-de-retorno">Covariación de tipos de retorno</h2>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ParentType</span> </span>{}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ChildType</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ParentType</span> </span>{}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">A</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">covariantReturnTypes</span>(<span class="hljs-params"></span>): <span class="hljs-title">ParentType</span>
    </span>{ <span class="hljs-comment">/* … */</span> }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">B</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">A</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">covariantReturnTypes</span>(<span class="hljs-params"></span>): <span class="hljs-title">ChildType</span>
    </span>{ <span class="hljs-comment">/* … */</span> }
}
</code></pre><h2 id="contravariacion-de-argumentos">Contravariación de argumentos</h2>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ParentType</span> </span>{}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ChildType</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ParentType</span> </span>{}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">A</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">contraVariantArguments</span>(<span class="hljs-params">ChildType $type</span>)
    </span>{ <span class="hljs-comment">/* … */</span> }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">B</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">A</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">contraVariantArguments</span>(<span class="hljs-params">ParentType $type</span>)
    </span>{ <span class="hljs-comment">/* … */</span> }
}
</code></pre><h2 id="null-coalescing-assignment-operator-en-php-74">Null coalescing assignment operator en PHP 7.4</h2>
<p>El operador de coalescencia nos permitía de una forma corta, asignar un valor null en caso de que la primera condición no se cumpliera, ejemplo:</p>
<pre><code>$variable = <span class="hljs-keyword">$this</span>-&gt;getParameter(<span class="hljs-string">'id'</span>) ?? <span class="hljs-literal">null</span>;
</code></pre><p>Ahora podremos resumirlo aún más usando:</p>
<pre><code>$variable ??= <span class="hljs-keyword">$this</span>-&gt;getParameter(<span class="hljs-string">'id'</span>);
</code></pre><h2 id="array-spread-operator-rfchttpswikiphpnetrfcspreadoperatorforarray">Array spread operator <a target="_blank" href="https://wiki.php.net/rfc/spread_operator_for_array">RFC</a></h2>
<p>Ahora es posible usar el operador de propagación en arrays, veamos un ejemplo:</p>
<pre><code><span class="hljs-string">$arrayA</span> <span class="hljs-string">=</span> [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]<span class="hljs-string">;</span>

<span class="hljs-string">$arrayB</span> <span class="hljs-string">=</span> [<span class="hljs-number">4</span>, <span class="hljs-number">5</span>]<span class="hljs-string">;</span>

<span class="hljs-string">$result</span> <span class="hljs-string">=</span> [<span class="hljs-number">0</span>, <span class="hljs-string">...$arrayA</span>, <span class="hljs-string">...$arrayB</span>, <span class="hljs-number">6</span> ,<span class="hljs-number">7</span>]<span class="hljs-string">;</span>

<span class="hljs-string">//output</span> <span class="hljs-string">will</span> <span class="hljs-string">be..</span>
[<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>]
</code></pre><blockquote>
<p><em>Esto solo funciona con arrays que contengan keys numéricos.</em>
<em>Nota.</em></p>
</blockquote>
<h2 id="numeric-literal-separator-rfchttpswikiphpnetrfcnumericliteralseparator">Numeric Literal Separator <a target="_blank" href="https://wiki.php.net/rfc/numeric_literal_separator">RFC</a></h2>
<p>PHP 7.4 permite usar underscores o guiones bajos para visualmente separar valores numéricos, ejemplo:</p>
<pre><code>$unformattedNumber = <span class="hljs-number">107925284.88</span>;

$formattedNumber = <span class="hljs-number">107</span>_925_284<span class="hljs-number">.88</span>;
</code></pre><p>Los “_” serán ignorados por el motor de PHP.</p>
<h2 id="preloading">Preloading</h2>
<p>Otro de los features de bajo nivel es el precargado. Es una adición sorprendente al núcleo de PHP, lo cual puede resultar en una significante mejora de rendimiento.</p>
<p>En pocas palabras, si utilizas un framework, los archivos de clases y demás deben ser cargados y enlazados en cada petición. La Precarga le permite al servidor cargar los archivos PHP en memoria en el arranque, y luego ponerlos permanentemente disponibles para todas las peticiones posteriores.</p>
<p>La ganancia de rendimiento tiene, por supuesto, un costo: si se cambia la fuente de los archivos precargados, el servidor debe reiniciarse.</p>
<h2 id="custom-object-serialization">Custom object serialization</h2>
<p>Dos nuevos métodos mágicos han sido añadidos para el release de esta versión: <code>__serialize</code>y <code>__unserialize</code>. La diferencia entre estos metodos y <code>__sleep</code> y <code>__wakeup</code> es tan expuestas en el RFC discussed in the <a target="_blank" href="https://wiki.php.net/rfc/custom_object_serialization">**RFC</a>**.</p>
<h2 id="deprecations">Deprecations</h2>
<p>Las siguientes funciones/funcionalidades serán deprecadas con PHP 7.4. para ver una lista más detallada puedes leer las notas de <a target="_blank" href="https://github.com/php/php-src/blob/PHP-7.4/UPGRADING">Actualización de PHP 7.4.</a></p>
<p>Estas son las novedades mas importantes que vendrán en noviembre, si quieres conocer más sobre lo que vendrá puedes echarle un ojo a este <a target="_blank" href="https://wiki.php.net/rfc">**link</a>**.</p>
<p>Recuerda que si tienes alguna sugerencia o pregunta, no dudes en dejar tus comentarios al final del post.</p>
<p>Si te gustó este post, ayúdame a que pueda servirle a muchas más personas, compartiendo mis contenidos en tus redes sociales.</p>
<p>Espero que este post haya sido de gran ayuda para ti, y como siempre, cualquier inquietud o duda que tengas, puedes contactarme por cualquiera de las vías disponibles, o dejando tus comentarios al final de este post. También puedes sugerir que temas o post te gustaría leer a futuro.</p>
]]></content:encoded></item><item><title><![CDATA[Introducción a la Arquitectura Hexagonal — Ep. 5 #CodingRocks]]></title><description><![CDATA[La arquitectura de software se ha convertido hoy en pilar fundamental de cada desarrollo y es por eso que hoy quiero compartir contigo en este episodio, una pequeña y sencilla introducción a la arquitectura hexagonal, la cual se ha vuelto muy común p...]]></description><link>https://franciscougalde.com/introduccion-a-la-arquitectura-hexagonal-ep-5-codingrocks</link><guid isPermaLink="true">https://franciscougalde.com/introduccion-a-la-arquitectura-hexagonal-ep-5-codingrocks</guid><category><![CDATA[software architecture]]></category><category><![CDATA[clean code]]></category><category><![CDATA[software development]]></category><category><![CDATA[software]]></category><category><![CDATA[oop]]></category><dc:creator><![CDATA[Francisco Ugalde]]></dc:creator><pubDate>Fri, 09 Aug 2019 15:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628328918440/RrGzw6AVl.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>La arquitectura de software se ha convertido hoy en pilar fundamental de cada desarrollo y es por eso que hoy quiero compartir contigo en este episodio, una pequeña y sencilla introducción a la arquitectura hexagonal, la cual se ha vuelto muy común para muchos desarrolladores y que supone muchísimos beneficios a la hora de desarrollar software.</p>
<p>Acompáñame en este nuevo episodio a conocer un poco mas sobre este tema y a mejorar día a día tus habilidades como programador web.</p>
<p>Recuerda que si tienes alguna sugerencia o pregunta, no dudes en dejar tus comentarios al final del post.</p>
<p>Si te gustó este post, ayúdame a que pueda servirle a muchas más personas, compartiendo mis contenidos en tus redes sociales.</p>
<p>Espero que este post haya sido de gran ayuda para ti, y como siempre, cualquier inquietud o duda que tengas, puedes contactarme por cualquiera de las vías disponibles, o dejando tus comentarios al final de este post. También puedes sugerir que temas o post te gustaría leer a futuro.</p>
]]></content:encoded></item></channel></rss>