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

<channel>
	<title>Show me the code</title>
	<atom:link href="http://showmethecode.es/feed/" rel="self" type="application/rss+xml" />
	<link>http://showmethecode.es</link>
	<description>Talk is cheap. Show me the code</description>
	<lastBuildDate>Sat, 14 Jun 2014 18:16:34 +0000</lastBuildDate>
	<language>es-ES</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=3.9.25</generator>
	<item>
		<title>Doctrine2: Join sin relación</title>
		<link>http://showmethecode.es/php/symfony/doctrine2-join-sin-relacion/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=doctrine2-join-sin-relacion</link>
		<comments>http://showmethecode.es/php/symfony/doctrine2-join-sin-relacion/#comments</comments>
		<pubDate>Mon, 12 May 2014 07:00:43 +0000</pubDate>
		<dc:creator><![CDATA[Fran Moreno]]></dc:creator>
				<category><![CDATA[Doctrine2]]></category>
		<category><![CDATA[Symfony]]></category>

		<guid isPermaLink="false">http://showmethecode.es/?p=2173</guid>
		<description><![CDATA[Últimamente tengo poco tiempo, pero no quiero perder la costumbre de escribir artículos aunque sean cortos como es este caso. Además, últimamente hemos recibido varios correos proponiendo temas para hacer artículos y eso se agradece mucho! En este caso, Manuel Aguirre, nos recomendó hacer un artículo sobre la posibilidad de hacer Joins en Doctrine2 sin necesidad]]></description>
				<content:encoded><![CDATA[<p>Últimamente tengo poco tiempo, pero no quiero perder la costumbre de escribir artículos aunque sean cortos como es este caso. Además, últimamente hemos recibido varios correos proponiendo temas para hacer artículos y eso se agradece mucho! En este caso, <a title="Manuel Aguirre" href="https://twitter.com/manuel_j555">Manuel Aguirre</a>, nos recomendó hacer un artículo sobre la posibilidad de hacer <strong>Joins en Doctrine2 sin necesidad de que tengan una relación directa</strong>.<span id="more-2173"></span></p>
<p>A veces creamos relaciones en las entities para poder hacer consultas, por ejemplo, si tuviéramos una entidad User y otra Country y queremos obtener los usuarios de un país, lo que podemos hacer es añadir a la entidad Country un atributo $users y podemos hacer la consulta en DQL así:</p><pre class="crayon-plain-tag">SELECT u.name, c.name
FROM SMTCBundle:Country c
JOIN c.users u</pre><p>A partir de la versión 2.3 de Doctrine, se puede hacer lo siguiente:</p><pre class="crayon-plain-tag">SELECT u.name, c.name
FROM SMTCBundle:Country c
JOIN SMTCBundle:User u WITH u.country = c.id</pre><p>De esta forma <strong>no es necesario</strong> que Country tenga un <strong>atributo</strong> $users que sólo lo usamos para cuando hacemos consultas. Los Join se pueden usar tanto en DQL como con QueryBuilder.</p>
]]></content:encoded>
			<wfw:commentRss>http://showmethecode.es/php/symfony/doctrine2-join-sin-relacion/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>deSymfonyDay 2014 en Barcelona!</title>
		<link>http://showmethecode.es/php/symfony/desymfonyday-2014-en-barcelona/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=desymfonyday-2014-en-barcelona</link>
		<comments>http://showmethecode.es/php/symfony/desymfonyday-2014-en-barcelona/#comments</comments>
		<pubDate>Mon, 14 Apr 2014 07:00:56 +0000</pubDate>
		<dc:creator><![CDATA[Fran Moreno]]></dc:creator>
				<category><![CDATA[Symfony]]></category>
		<category><![CDATA[deSymfonyDay]]></category>

		<guid isPermaLink="false">http://showmethecode.es/?p=2162</guid>
		<description><![CDATA[Este año en principio no se iba a celebrar deSymfony porque entre otras cosas se celebrará en Madrid la Symfony Con, pero la semana pasada un tweet de Raúl Fraile propició una serie de reacciones por parte de la comunidad Symfony y en menos de usa semana ya se ha decidido que el día 31]]></description>
				<content:encoded><![CDATA[<p>Este año en principio <a title="desymfony symfony con" href="http://desymfony.com/noticias/desymfony-descansara-en-2014-dando-la-bienvenida-a-symfonycon-madrid">no se iba a celebrar deSymfony porque entre otras cosas se celebrará en Madrid la Symfony Con</a>, pero la semana pasada <a title="Raúl Fraile twit" href="https://twitter.com/raulfraile/status/453453861643362304">un tweet de Raúl Fraile</a> propició una serie de reacciones por parte de la <strong>comunidad Symfony</strong> y <strong>en menos de usa semana</strong> <a title="desymfonyday symfony.es" href="http://symfony.es/noticias/2014/04/11/desymfonyday-vuelve-la-magia-de-desymfony/">ya se ha decidido</a> que el <strong>día 31 de mayo</strong> habrá un <strong>deSymfonyDay</strong> en <strong>Barcelona</strong>!<span id="more-2162"></span></p>
<h2><a title="deSymfonyDay" href="http://day.desymfony.com">day.desymfony.com</a></h2>
<p>Podéis ver toda la información en la web del evento. Animaos y mandad vuestras propuestas de charla!!</p>
<p>Nos vemos en Barcelona!</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://showmethecode.es/php/symfony/desymfonyday-2014-en-barcelona/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Symfony2: Asignar el usuario logueado a una entidad automáticamente</title>
		<link>http://showmethecode.es/php/symfony/symfony2-asignar-el-usuario-logueado-a-una-entidad-automaticamente/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=symfony2-asignar-el-usuario-logueado-a-una-entidad-automaticamente</link>
		<comments>http://showmethecode.es/php/symfony/symfony2-asignar-el-usuario-logueado-a-una-entidad-automaticamente/#comments</comments>
		<pubDate>Mon, 07 Apr 2014 07:00:49 +0000</pubDate>
		<dc:creator><![CDATA[Fran Moreno]]></dc:creator>
				<category><![CDATA[Doctrine2]]></category>
		<category><![CDATA[Symfony]]></category>
		<category><![CDATA[Symfony2]]></category>

		<guid isPermaLink="false">http://showmethecode.es/?p=2086</guid>
		<description><![CDATA[Es posible que en nuestra aplicación tengamos algunas Entities que dependen del usuario que está conectado, es decir, tienen un atributo $user, por ejemplo, que debe almacenar al usuario de la sesión. Vamos a ver una forma de hacer esto automáticamente con los eventos de Doctrine. Lo primero que haremos será crearnos una interfaz UserAware:]]></description>
				<content:encoded><![CDATA[<p>Es posible que en nuestra aplicación tengamos algunas Entities que dependen del usuario que está conectado, es decir, tienen un atributo $user, por ejemplo, que debe almacenar al usuario de la sesión. Vamos a ver una forma de hacer esto <strong>automáticamente</strong> con los <strong>eventos de Doctrine.</strong><span id="more-2086"></span></p>
<p>Lo primero que haremos será crearnos una interfaz UserAware:</p><pre class="crayon-plain-tag">namespace SMTC\Bundle\MainBundle\Entity;

interface UserAware
{
    /**
     * Sets the user
     *
     * @param UserInterface|null $user A user instance or null
     */
    public function setUser(UserInterface $user = null);
}</pre><p>Y la implementamos en las entities en las que guardamos el usuario, por ejemplo:</p><pre class="crayon-plain-tag">namespace SMTC\Bundle\MainBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Training
 *
 * @ORM\Table(name="main_training")
 * @ORM\Entity
 */
class Training implements UserAware
{
    // ...

    /**
     * @ORM\ManyToOne(targetEntity="User")
     * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
     */
    private $user;

    // ...

    public function setUser(UserInterface $user = null)
    {
        $this-&gt;user = $user;
    }
}</pre><p>Ahora ya sólo nos queda la parte <a title="Doctrine2 Listener" href="http://symfony.com/doc/current/cookbook/doctrine/event_listeners_subscribers.html">del listener de Doctrine</a>. En el listener lo que haremos será mirar si la entidad que se va a persistir implementa la interfaz UserAware, en cuyo caso se le asignará el usuario de la sesión. Aquí hay un problema y es que no se puede crear un Listener de Doctrine e inyectarle el servicio <em>security.context</em> para recuperar al usuario porque nos da un error de <strong>dependencia circular</strong>. Una de las opciones es crearnos un servicio aparte del que podamos recuperar el usuario y este servicio será el que inyectemos al Listener de Doctrine. Vamos a usar la implementación que tienen en <a title="DoctrineBehaviours" href="https://github.com/KnpLabs/DoctrineBehaviors/blob/master/src/Knp/DoctrineBehaviors/ORM/Blameable/UserCallable.php">DoctrineBehaviours</a> de esto:</p><pre class="crayon-plain-tag">namespace SMTC\Bundle\MainBundle\Doctrine;

use Symfony\Component\DependencyInjection\ContainerInterface;
use SMTC\Bundle\MainBundle\Entity\UserInterface;

/**
 * UserCallable can be invoked to return a blameable user
 * @see https://github.com/KnpLabs/DoctrineBehaviors/blob/master/src/Knp/DoctrineBehaviors/ORM/Blameable/UserCallable.php
 */
class UserCallable
{
    /**
     * @var ContainerInterface
     */
    private $container;

    public function __construct(ContainerInterface $container)
    {
        $this-&gt;container = $container;
    }

    public function __invoke()
    {
        $token = $this-&gt;container-&gt;get('security.context')-&gt;getToken();
        if (null !== $token) {
            return $token-&gt;getUser();
        }
    }
}</pre><p>Y declaramos este servicio:</p><pre class="crayon-plain-tag">&lt;!-- src/SMTC/Bundle/MainBundle/Resources/config/security.xml --&gt;

&lt;service id="smtc.security.user_callable" class="SMTC\Bundle\MainBundle\Security\UserCallable"&gt;
    &lt;argument type="service" id="service_container" /&gt; &lt;!-- because of circular dep --&gt;
&lt;/service&gt;</pre><p>Ahora ya podemos crear nuestro Listener en Doctrine:</p><pre class="crayon-plain-tag">&lt;?php

namespace SMTC\Bundle\MainBundle\Doctrine;

use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Events;
use SMTC\Bundle\MainBundle\Entity\UserAware;

class UserSubscriber implements EventSubscriber
{
    protected $userCallable;

    public function __construct(callable $userCallable)
    {
        $this-&gt;userCallable = $userCallable;
    }

    /**
     * @param LifecycleEventArgs $args
     */
    public function prePersist(LifecycleEventArgs $args)
    {
        $object = $args-&gt;getEntity();
        if ($object instanceof UserAware) {
            $user = $this-&gt;getLoggedUser();
            $object-&gt;setUser($user);
        }
    }

    private function getLoggedUser()
    {
        $callable = $this-&gt;userCallable;
        $user = $callable();

        return $user;
    }

    public function getSubscribedEvents()
    {
        return array(
            Events::prePersist,
        );
    }
}</pre><p>Y declararlo como servicio con el <strong>tag</strong> para que <strong>doctrine</strong> sepa que es un <strong>subscriber</strong>:</p><pre class="crayon-plain-tag">&lt;!-- src/SMTC/Bundle/MainBundle/Resources/config/doctrine.xml --&gt;

&lt;service id="smtc.doctrine_subscriber.user_aware" class="SMTC\Bundle\MainBundle\Doctrine\UserSubscriber"&gt;
    &lt;argument type="service" id="smtc.security.user_callable" /&gt;
    &lt;tag name="doctrine.event_subscriber"/&gt;
&lt;/service&gt;</pre><p>Ahora, cada vez que se persista una entidad que implemente la interfaz UserAware, se le asignará automáticamente el usuario de la sesión.</p>
]]></content:encoded>
			<wfw:commentRss>http://showmethecode.es/php/symfony/symfony2-asignar-el-usuario-logueado-a-una-entidad-automaticamente/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Symfony2: Acceder al usuario logueado</title>
		<link>http://showmethecode.es/php/symfony/symfony2-acceder-al-usuario-logueado/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=symfony2-acceder-al-usuario-logueado</link>
		<comments>http://showmethecode.es/php/symfony/symfony2-acceder-al-usuario-logueado/#comments</comments>
		<pubDate>Mon, 31 Mar 2014 07:10:16 +0000</pubDate>
		<dc:creator><![CDATA[Fran Moreno]]></dc:creator>
				<category><![CDATA[Symfony]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Symfony2]]></category>

		<guid isPermaLink="false">http://showmethecode.es/?p=2149</guid>
		<description><![CDATA[En el artículo de hoy vamos a ver cómo recuperar el usuario conectado en la aplicación desde un controlador o servicio y en Twig. También veremos cómo comprobar si el usuario está conectado. Lo primero que tenemos que tener bien configurado es la seguridad de la aplicación, esto está explicado en el manual de Symfony. Desde]]></description>
				<content:encoded><![CDATA[<p>En el artículo de hoy vamos a ver cómo recuperar el usuario conectado en la aplicación desde un controlador o servicio y en Twig. También veremos cómo comprobar si el usuario está conectado.</p>
<p><span id="more-2149"></span></p>
<p>Lo primero que tenemos que tener bien configurado es la seguridad de la aplicación, esto está explicado en <a title="Seguridad Symfony2" href="http://librosweb.es/symfony_2_x/capitulo_13.html">el manual de Symfony</a>.</p>
<div class="headline no-margin"><h3>Acceder al usuario logueado</h3></div>
<p>Desde el controlador, si extendemos de <pre class="crayon-plain-tag">Symfony\Bundle\FrameworkBundle\Controller\Controller</pre> tenemos acceso al método <em><a title="getUser" href="https://github.com/symfony/symfony/blob/2.4/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php#L218">getUser</a> </em>(a partir de la versión 2.1 si no recuerdo mal), por lo que podemos llamar a este método y obtener el usuario.</p><pre class="crayon-plain-tag">use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class UserController extends Controller
{
    public function showAction()
    {
        $user = $this-&gt;getUser();

        // ...
    {
}</pre><p>Viendo el código de este método vamos a ver cómo podemos obtener el usuario en otros servicios:</p><pre class="crayon-plain-tag">public function getUser()
{
    if (!$this-&gt;container-&gt;has('security.context')) {
        throw new \LogicException('The SecurityBundle is not registered in your application.');
    }

    if (null === $token = $this-&gt;container-&gt;get('security.context')-&gt;getToken()) {
        return null;
    }

    if (!is_object($user = $token-&gt;getUser())) {
        return null;
    }

    return $user;
}</pre><p>Para obtener el usuario hay que acceder al servicio <em>security.context</em>, de ahí obtener el token y de ahí obtener el usuario, es decir:</p><pre class="crayon-plain-tag">$user = $this-&gt;container-&gt;get('security.context')-&gt;getToken()-&gt;getUser();</pre><p>Por lo que si desde un servicio queremos acceder al usuario, podemos inyectarle el servicio <em>security.context</em> y recuperarlo de ahí. Puede que según nuestra aplicación, necesitemos ejecutar o hacer comprobaciones cuando recuperamos el usuario, en ese caso se puede crear un servicio que sea el encargado de recuperar el usuario y hacer estas operaciones y será este servicio el que pasemos a los demás servicios para recuperar el usuario. Esto lo usaremos en uno de los próximos artículos.</p>
<p>Desde Twig podemos accedemos al usuario con:</p><pre class="crayon-plain-tag">{{ app.user }}</pre><p><em>app</em> es una variable global disponible en cualquier plantilla.</p>
<div class="headline no-margin"><h3>Comprobar que el usuario está logueado</h3></div>
<p>Desde un controller o servicio esta operación se hace también a través del <em>security.context</em>, lo que tenemos que hacer es comprobar si el usuario tiene un rol especial llamado <em>IS_AUTHENTICATED_FULLY</em> o <em>IS_AUTHENTICATED_REMEMBERED</em>:</p><pre class="crayon-plain-tag">use Symfony\Component\Security\Core\Exception\AccessDeniedException;

public function helloAction($name)
{
    if (false === $this-&gt;get('security.context')-&gt;isGranted('IS_AUTHENTICATED_FULLY')) {
        throw new AccessDeniedException();
    }

    // ...
}</pre><p>¿Cuál es la diferencia? El rol <em>IS_AUTHENTICATED_FULLY</em> requiere que estés logueado en esa misma sesión, esto es útil por ejemplo cuando se quiere acceder al perfil del usuario para que cambie la contraseña. El rol <em>IS_AUTHENTICATED_REMEMBERED</em> permite que estés autenticado mediante la cookie de rembember-me.</p>
<p>En Twig se puede comprobar lo mismo con la función <em>is_granted</em>:</p><pre class="crayon-plain-tag">{% if is_granted('IS_AUTHENTICATED_FULLY') %}
    &lt;a href="..."&gt;Delete&lt;/a&gt;
{% endif %}</pre><p></p>
]]></content:encoded>
			<wfw:commentRss>http://showmethecode.es/php/symfony/symfony2-acceder-al-usuario-logueado/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Configurar Behat, Mink y Selenium2 para usar Chrome</title>
		<link>http://showmethecode.es/php/symfony/configurar-behat-mink-y-selenium2-para-usar-chrome/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=configurar-behat-mink-y-selenium2-para-usar-chrome</link>
		<comments>http://showmethecode.es/php/symfony/configurar-behat-mink-y-selenium2-para-usar-chrome/#comments</comments>
		<pubDate>Mon, 24 Mar 2014 08:00:06 +0000</pubDate>
		<dc:creator><![CDATA[Fran Moreno]]></dc:creator>
				<category><![CDATA[Symfony]]></category>
		<category><![CDATA[Behat]]></category>
		<category><![CDATA[Mink]]></category>
		<category><![CDATA[Symfony2]]></category>

		<guid isPermaLink="false">http://showmethecode.es/?p=2138</guid>
		<description><![CDATA[El otro día Alfonso nos dio una buena charla sobre Behat en Symfony Valencia. La charla es una introducción a Behat viendo los problemas que resuelve y cómo puede cambiar nuestra forma de trabajar. En el artículo de hoy veremos cómo configurarlo para lanzar nuestros escenarios con Chrome. Partimos de esta configuración: [crayon-5bf4486f82786080304290/] Con el servidor de]]></description>
				<content:encoded><![CDATA[<p>El otro día <a title="Alfonso Machado" href="https://twitter.com/almacbe">Alfonso</a> nos dio <a title="Behat Youtube" href="https://www.youtube.com/watch?v=hv86KlgDWOw">una buena charla sobre Behat</a> en <a href="http://www.symfony-valencia.es/">Symfony Valencia</a>. La charla es una introducción a <a title="Behat" href="http://behat.org/">Behat</a> viendo los problemas que resuelve y cómo puede cambiar nuestra forma de trabajar. En el artículo de hoy veremos cómo configurarlo para lanzar nuestros escenarios con Chrome.<span id="more-2138"></span></p>
<p>Partimos de esta configuración:</p><pre class="crayon-plain-tag">default:
    extensions:
        Behat\Symfony2Extension\Extension:
            mink_driver: true
            kernel:
                env: test
                debug: true
        Behat\MinkExtension\Extension:
            base_url: http://example.local/app_test.php
            default_session: symfony2
            browser_name: firefox
            javascript_session: selenium2
            selenium2: ~</pre><p>Con el servidor de Selenium lanzado:</p><pre class="crayon-plain-tag">$ java -jar selenium-server-standalone-2.40.0.jar</pre><p>Y ejecutamos behat:</p><pre class="crayon-plain-tag">$ bin/behat @AcmeBundle --config=app/config/behat.yml --tags=javascript</pre><p>Con esta configuración los escenarios que están marcados con el tag <em>@javascript</em> se lanzarán con firefox. Para que se lancen con Chrome lo primero es cambiar <em>browser_name</em> a <em>chrome</em>.</p><pre class="crayon-plain-tag">default:
    extensions:
        Behat\Symfony2Extension\Extension:
            mink_driver: true
            kernel:
                env: test
                debug: true
        Behat\MinkExtension\Extension:
            base_url: http://example.local/app_test.php
            default_session: symfony2
            browser_name: chrome
            javascript_session: selenium2
            selenium2: ~</pre><p>Si ahora lanzamos nuestros escenarios obtendremos el error:</p>
<blockquote><p>Could not open connection: The path to the driver executable must be set by the webdriver.chrome.driver system property; for more information, see http://code.google.com/p/selenium/wiki/ChromeDriver. The latest version can be downloaded from http://chromedriver.storage.googleapis.com/index.html</p></blockquote>
<p>Vamos a la página web que nos indica y nos bajamos la última versión del driver para nuestro sistema operativo. El fichero se llama <em>chromedriver</em>, ahora sólo falta añadir un parámetro a la ejecución del servidor de Selenium indicando la ruta al driver (si lo tenemos en el mismo directorio que Selenium no hace falta), de modo que ahora ejecutamos:</p><pre class="crayon-plain-tag">$ java -jar selenium-server-standalone-2.40.0.jar -Dwebdriver.chrome.driver=chromedriver</pre><p>Y a partir de ahora ya podremos ejecutar los escenarios en Chrome.</p>
<p>Para acabar, cuando queremos mostrar la última respuesta con el step <em>show last response</em> en Mac, debemos añadir el parámetro <em>show_cmd</em> con el siguiente valor:</p><pre class="crayon-plain-tag">default:
    extensions:
        Behat\Symfony2Extension\Extension:
            mink_driver: true
            kernel:
                env: test
                debug: true
        Behat\MinkExtension\Extension:
            base_url: http://example.local/app_test.php
            default_session: symfony2
            browser_name: chrome
            javascript_session: selenium2
            selenium2: ~
            show_cmd: open -a Google\ Chrome %s</pre><p></p>
]]></content:encoded>
			<wfw:commentRss>http://showmethecode.es/php/symfony/configurar-behat-mink-y-selenium2-para-usar-chrome/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Symfony2.4: Dependent Forms</title>
		<link>http://showmethecode.es/php/symfony/symfony2-4-dependent-forms/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=symfony2-4-dependent-forms</link>
		<comments>http://showmethecode.es/php/symfony/symfony2-4-dependent-forms/#comments</comments>
		<pubDate>Mon, 17 Mar 2014 08:00:12 +0000</pubDate>
		<dc:creator><![CDATA[Fran Moreno]]></dc:creator>
				<category><![CDATA[Symfony]]></category>
		<category><![CDATA[Dependent Forms]]></category>
		<category><![CDATA[Forms]]></category>
		<category><![CDATA[Symfony2]]></category>

		<guid isPermaLink="false">http://showmethecode.es/?p=2113</guid>
		<description><![CDATA[I wanted to update my post about Dependent Selects because there is some deprecated code in it and I also wanted to write a post in English, so here we are! We will see how to implement Dependent Forms using Form events in detail. We are going to implement the typical Country, Province and City]]></description>
				<content:encoded><![CDATA[<p>I wanted to update <a title="Symfony2: Selects dependientes mediante eventos" href="http://showmethecode.es/php/symfony/symfony2-selects-dependientes-mediante-eventos/">my post about Dependent Selects</a> because there is some deprecated code in it and I also wanted to write a post in English, so here we are! We will see how to implement Dependent Forms using Form events in detail.<span id="more-2113"></span></p>
<p>We are going to implement the typical <a title="Country" href="https://github.com/showmethecodeteam/showmethecode/blob/master/src/SMTC/MainBundle/Entity/Country.php">Country</a>, <a title="Province" href="https://github.com/showmethecodeteam/showmethecode/blob/master/src/SMTC/MainBundle/Entity/Province.php">Province</a> and <a title="City" href="https://github.com/showmethecodeteam/showmethecode/blob/master/src/SMTC/MainBundle/Entity/City.php">City</a> example:</p>
<p><img class="alignnone" alt=" Symfony2.4: Dependent Forms" src="http://yuml.me/bf8ad926" width="557" height="72" title="Symfony2.4: Dependent Forms" /></p>
<p>Location is the model where we have the a City attribute:</p><pre class="crayon-plain-tag">namespace SMTC\MainBundle\Model;

use Symfony\Component\Validator\Constraints as Assert;

class Location
{
    /**
     * @Assert\NotBlank()
     */
    public $address;

    /**
     * @Assert\Type("SMTC\MainBundle\Entity\City")
     * @Assert\NotNull()
     */
    public $city;
}</pre><p>Before we write the Form Type, we have to think about what we want to do. We want a Form Type with 4 fields, <strong>address</strong> will be a <em>text</em> field, <strong>city</strong> will be an <em>entity</em> field and the available choices will depend on the <strong>province</strong> field, this province will depend on <strong>country</strong>. When we have to add fields to a form which depend on other fields we have to use <strong>Form Events</strong>. Let&#8217;s see the implementation.</p>
<p>Our LocationType looks like this:</p><pre class="crayon-plain-tag">namespace SMTC\MainBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use SMTC\MainBundle\Form\EventListener\AddCityFieldSubscriber;
use SMTC\MainBundle\Form\EventListener\AddProvinceFieldSubscriber;
use SMTC\MainBundle\Form\EventListener\AddCountryFieldSubscriber;

class LocationType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $propertyPathToCity = 'city';

        $builder
            -&gt;addEventSubscriber(new AddCityFieldSubscriber($propertyPathToCity))
            -&gt;addEventSubscriber(new AddProvinceFieldSubscriber($propertyPathToCity))
            -&gt;addEventSubscriber(new AddCountryFieldSubscriber($propertyPathToCity))
        ;

        $builder
            -&gt;add('address', 'text', array(
                'label' =&gt; 'Calle'
            ))
        ;
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver-&gt;setDefaults(array(
            'data_class' =&gt; 'SMTC\MainBundle\Model\Location'
        ));
    }

    public function getName()
    {
        return 'location';
    }
}</pre><p>As we said before, we have used listeners that will add <em>city</em>, <em>province</em> and <em>country</em> dynamically. We will see the implementation later, but first, we have to <strong>understand how Form Events work</strong>. I highly recommend you to read <a title="dynamic_form_modification" href="http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html">the Symfony documentation about dynamic form</a>.</p>
<p>So, <strong>which events do we have to listen to</strong>?</p>
<p>We can find two scenarios, the first one is when we have to <strong>modify the form based on the underlying data</strong>, that is when we have our form populated with our model. And the other one is when the <strong>form should change depending on the data sent from the user</strong>, that is when the form is populated with the submitted data.</p>
<p><span style="line-height: 1.5em;">So we need our listeners to listen to </span><strong style="line-height: 1.5em;">PRE_SET_DATA</strong><span style="line-height: 1.5em;"> and </span><strong style="line-height: 1.5em;">PRE_SUBMIT</strong><span style="line-height: 1.5em;"> events. These two events are called just before populating the form (<em>PRE_SET_DATA</em> with the model data and <em>PRE_SUBMIT</em> with the submitted data). Our AddCityFieldSubscriber looks like:</span></p><pre class="crayon-plain-tag">namespace SMTC\MainBundle\Form\EventListener;

use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Doctrine\ORM\EntityRepository;
use SMTC\MainBundle\Entity\Province;
use SMTC\MainBundle\Entity\City;

class AddCityFieldSubscriber implements EventSubscriberInterface
{
    private $propertyPathToCity;

    public function __construct($propertyPathToCity)
    {
        $this-&gt;propertyPathToCity = $propertyPathToCity;
    }

    public static function getSubscribedEvents()
    {
        return array(
            FormEvents::PRE_SET_DATA  =&gt; 'preSetData',
            FormEvents::PRE_SUBMIT    =&gt; 'preSubmit'
        );
    }

    private function addCityForm($form, $province_id)
    {
        $formOptions = array(
            'class'         =&gt; 'MainBundle:City',
            'empty_value'   =&gt; 'Ciudad',
            'label'         =&gt; 'Ciudad',
            'attr'          =&gt; array(
                'class' =&gt; 'city_selector',
            ),
            'query_builder' =&gt; function (EntityRepository $repository) use ($province_id) {
                $qb = $repository-&gt;createQueryBuilder('city')
                    -&gt;innerJoin('city.province', 'province')
                    -&gt;where('province.id = :province')
                    -&gt;setParameter('province', $province_id)
                ;

                return $qb;
            }
        );

        $form-&gt;add($this-&gt;propertyPathToCity, 'entity', $formOptions);
    }

    public function preSetData(FormEvent $event)
    {
        $data = $event-&gt;getData();
        $form = $event-&gt;getForm();

        if (null === $data) {
            return;
        }

        $accessor    = PropertyAccess::createPropertyAccessor();

        $city        = $accessor-&gt;getValue($data, $this-&gt;propertyPathToCity);
        $province_id = ($city) ? $city-&gt;getProvince()-&gt;getId() : null;

        $this-&gt;addCityForm($form, $province_id);
    }

    public function preSubmit(FormEvent $event)
    {
        $data = $event-&gt;getData();
        $form = $event-&gt;getForm();

        $province_id = array_key_exists('province', $data) ? $data['province'] : null;

        $this-&gt;addCityForm($form, $province_id);
    }
}</pre><p>In the preSetData method, the data we receive is <strong>from the model</strong>, so it will be an instance of the model, Location in this case. We use PropertyAccess because in Location, <em>city</em> is a public attribute, but if we want to use this listener with an Entity for example, we would need to call <pre class="crayon-plain-tag">$data-&gt;getCity()</pre>  instead of <pre class="crayon-plain-tag">$data-&gt;city</pre> .</p>
<p>In the preSubmit method we receive the data from the view <strong>as an array</strong>.</p>
<p>Finally, we add the city field and depending on the value of province, it should only display the cities associated with the selected province.</p>
<p>The AddProvinceFieldSubscriber looks like:</p><pre class="crayon-plain-tag">namespace SMTC\MainBundle\Form\EventListener;

use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Doctrine\ORM\EntityRepository;
use SMTC\MainBundle\Entity\Country;

class AddProvinceFieldSubscriber implements EventSubscriberInterface
{
    private $propertyPathToCity;

    public function __construct($propertyPathToCity)
    {
        $this-&gt;propertyPathToCity = $propertyPathToCity;
    }

    public static function getSubscribedEvents()
    {
        return array(
            FormEvents::PRE_SET_DATA =&gt; 'preSetData',
            FormEvents::PRE_SUBMIT   =&gt; 'preSubmit'
        );
    }

    private function addProvinceForm($form, $country_id, $province = null)
    {
        $formOptions = array(
            'class'         =&gt; 'MainBundle:Province',
            'empty_value'   =&gt; 'Provincia',
            'label'         =&gt; 'Provincia',
            'mapped'        =&gt; false,
            'attr'          =&gt; array(
                'class' =&gt; 'province_selector',
            ),
            'query_builder' =&gt; function (EntityRepository $repository) use ($country_id) {
                $qb = $repository-&gt;createQueryBuilder('province')
                    -&gt;innerJoin('province.country', 'country')
                    -&gt;where('country.id = :country')
                    -&gt;setParameter('country', $country_id)
                ;

                return $qb;
            }
        );

        if ($province) {
            $formOptions['data'] = $province;
        }

        $form-&gt;add('province','entity', $formOptions);
    }

    public function preSetData(FormEvent $event)
    {
        $data = $event-&gt;getData();
        $form = $event-&gt;getForm();

        if (null === $data) {
            return;
        }

        $accessor = PropertyAccess::getPropertyAccessor();

        $city        = $accessor-&gt;getValue($data, $this-&gt;propertyPathToCity);
        $province    = ($city) ? $city-&gt;getProvince() : null;
        $country_id  = ($province) ? $province-&gt;getCountry()-&gt;getId() : null;

        $this-&gt;addProvinceForm($form, $country_id, $province);
    }

    public function preSubmit(FormEvent $event)
    {
        $data = $event-&gt;getData();
        $form = $event-&gt;getForm();

        $country_id = array_key_exists('country', $data) ? $data['country'] : null;

        $this-&gt;addProvinceForm($form, $country_id);
    }
}</pre><p></p>
<p dir="ltr">This is similar to the previous Listener, depending on the value of the Country, it displays the provinces associated with the selected Country. We don’t really want the province value in our model, so the <em>mapped</em> attributed is set to <em>false</em> and because of that, we need to pass the Province object to the addProvinceForm in order to show the selected province.</p>
<p dir="ltr">And finally AddCountryFieldSubscriber:</p>
<p></p><pre class="crayon-plain-tag">namespace SMTC\MainBundle\Form\EventListener;

use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Doctrine\ORM\EntityRepository;

class AddCountryFieldSubscriber implements EventSubscriberInterface
{
    private $propertyPathToCity;

    public function __construct($propertyPathToCity)
    {
        $this-&gt;propertyPathToCity = $propertyPathToCity;
    }

    public static function getSubscribedEvents()
    {
        return array(
            FormEvents::PRE_SET_DATA =&gt; 'preSetData',
            FormEvents::PRE_SUBMIT   =&gt; 'preSubmit'
        );
    }

    private function addCountryForm($form, $country = null)
    {
        $formOptions = array(
            'class'         =&gt; 'MainBundle:Country',
            'mapped'        =&gt; false,
            'label'         =&gt; 'País',
            'empty_value'   =&gt; 'País',
            'attr'          =&gt; array(
                'class' =&gt; 'country_selector',
            ),
        );

        if ($country) {
            $formOptions['data'] = $country;
        }

        $form-&gt;add('country', 'entity', $formOptions);
    }

    public function preSetData(FormEvent $event)
    {
        $data = $event-&gt;getData();
        $form = $event-&gt;getForm();

        if (null === $data) {
            return;
        }

        $accessor = PropertyAccess::getPropertyAccessor();

        $city    = $accessor-&gt;getValue($data, $this-&gt;propertyPathToCity);
        $country = ($city) ? $city-&gt;getProvince()-&gt;getCountry() : null;

        $this-&gt;addCountryForm($form, $country);
    }

    public function preSubmit(FormEvent $event)
    {
        $form = $event-&gt;getForm();

        $this-&gt;addCountryForm($form);
    }
}</pre><p>It is like AddProvinceFieldSubscriber, but Country doesn&#8217;t depend on any field.</p>
<p>This would be what we need to do with forms. We will also need two actions in a controller to fetch the list of provinces associated to a country and the list of cities associated to a province.</p><pre class="crayon-plain-tag">/**
 * @Route("/provinces", name="select_provinces")
 */
public function provincesAction(Request $request)
{
    $country_id = $request-&gt;request-&gt;get('country_id');

    $em = $this-&gt;getDoctrine()-&gt;getManager();
    $provinces = $em-&gt;getRepository('MainBundle:Province')-&gt;findByCountryId($country_id);

    return new JsonResponse($provinces);
}

/**
 * @Route("/cities", name="select_cities")
 */
public function citiesAction(Request $request)
{
    $province_id = $request-&gt;request-&gt;get('province_id');

    $em = $this-&gt;getDoctrine()-&gt;getManager();
    $cities = $em-&gt;getRepository('MainBundle:City')-&gt;findByProvinceId($province_id);

    return new JsonResponse($cities);
}</pre><p>And i<span style="line-height: 1.5em;">n the view we will need JavaScript for making those calls when one of the selects change, this would be an example of the JavaScript to update the cities select when the Province select changes:</span></p><pre class="crayon-plain-tag">$("#location_province").change(function(){
    var data = {
        province_id: $(this).val()
    };

    $.ajax({
        type: 'post',
        url: '{{ path("select_cities") }}',
        data: data,
        success: function(data) {
            var $city_selector = $('#location_city');

            $city_selector.html('&lt;option&gt;Ciudad&lt;/option&gt;');

            for (var i=0, total = data.length; i &lt; total; i++) {
                $city_selector.append('&lt;option value="' + data[i].id + '"&gt;' + data[i].name + '&lt;/option&gt;');
            }
        }
    });
});</pre><p>You can see the fully working example (with the code) here:</p>
<p style="text-align: center;"><a class="button medium color" href="http://sf2.showmethecode.es/app.php/ejemplo/selects-dependientes" > Ver Demo </a></p>
]]></content:encoded>
			<wfw:commentRss>http://showmethecode.es/php/symfony/symfony2-4-dependent-forms/feed/</wfw:commentRss>
		<slash:comments>35</slash:comments>
		</item>
		<item>
		<title>Symfony2: Constraints</title>
		<link>http://showmethecode.es/php/symfony/symfony2-constraints/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=symfony2-constraints</link>
		<comments>http://showmethecode.es/php/symfony/symfony2-constraints/#comments</comments>
		<pubDate>Mon, 10 Mar 2014 08:00:39 +0000</pubDate>
		<dc:creator><![CDATA[Fran Moreno]]></dc:creator>
				<category><![CDATA[Symfony]]></category>
		<category><![CDATA[Constaint]]></category>
		<category><![CDATA[Symfony2]]></category>
		<category><![CDATA[Validator]]></category>

		<guid isPermaLink="false">http://showmethecode.es/?p=2088</guid>
		<description><![CDATA[En este artículo vamos a cómo son los Constraints. En la documentación de Symfony hay una referencia a todas ellos, aquí vamos a ver las clases implicadas. Cuando en una Entity, modelo, en un formulario o donde sea usamos Constraints como NotBlank, NotNull, Email, etc. Realmente, ¿qué está pasando? Lo que estamos indicando es que]]></description>
				<content:encoded><![CDATA[<p>En este artículo vamos a cómo son los Constraints. En la documentación de Symfony <a title="Constraints" href="http://symfony.com/doc/current/reference/constraints.html">hay una referencia a todas ellos</a>, aquí vamos a ver las clases implicadas.<span id="more-2088"></span></p>
<p>Cuando en una Entity, modelo, en un formulario o donde sea usamos Constraints como <em>NotBlank</em>, <em>NotNull</em>, <em>Email</em>, etc. Realmente, ¿qué está pasando? Lo que estamos indicando es que estamos asociando que un determinado campo o clase (según donde lo apliquemos) debe cumplir con ese Constraint. Y ¿dónde está el código que se ejecuta para estas comprobaciones? Dentro del componente Validator, están definidas estos <a title="Constraints" href="https://github.com/symfony/symfony/tree/2.4/src/Symfony/Component/Validator/Constraints">Constraints</a>.</p>
<p>Vamos a ver <em><a title="NotNull" href="https://github.com/symfony/symfony/blob/2.4/src/Symfony/Component/Validator/Constraints/NotNull.php">NotNull</a>.</em> Todos las Constraints están divididos en dos clases, por una parte tenemos el propio Constraint:</p><pre class="crayon-plain-tag">namespace Symfony\Component\Validator\Constraints;

use Symfony\Component\Validator\Constraint;

/**
 * @Annotation
 *
 * @author Bernhard Schussek &lt;bschussek@gmail.com&gt;
 *
 * @api
 */
class NotNull extends Constraint
{
    public $message = 'This value should not be null.';
}</pre><p>Esta clase extiende de Constraint y aquí se definen las propiedades y configuración, en este caso el mensaje que aparecerá cuando no se cumpla. Destacar también la anotación <em>Annotation</em> que permite luego poder usar la clase en una anotación.</p>
<p>Por otra parte tenemos el Validator:</p><pre class="crayon-plain-tag">namespace Symfony\Component\Validator\Constraints;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

/**
 * @author Bernhard Schussek &lt;bschussek@gmail.com&gt;
 *
 * @api
 */
class NotNullValidator extends ConstraintValidator
{
    /**
     * {@inheritDoc}
     */
    public function validate($value, Constraint $constraint)
    {
        if (null === $value) {
            $this-&gt;context-&gt;addViolation($constraint-&gt;message);
        }
    }
}</pre><p>Esta clase es la que se va a encargar de tener la lógica de validación en el método validate, el cual recibe el valor a validar y la Constraint de configuración. A través del atributo <em>context</em> añadimos las violaciones en el caso que se produjeran.</p>
<p><strong>¿Qué cosas podemos configurar de la clase Constraint?</strong></p>
<p>Lo mejor es ver una ya hecha, vamos a usar de ejemplo el Constraint <a title="UniqueEntity" href="https://github.com/symfony/symfony/blob/2.4/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntity.php">UniqueEntity</a>:</p><pre class="crayon-plain-tag">use Symfony\Component\Validator\Constraint;

/**
 * Constraint for the Unique Entity validator
 *
 * @Annotation
 * @author Benjamin Eberlei &lt;kontakt@beberlei.de&gt;
 */
class UniqueEntity extends Constraint
{
    public $message = 'This value is already used.';
    public $service = 'doctrine.orm.validator.unique';
    public $em = null;
    public $repositoryMethod = 'findBy';
    public $fields = array();
    public $errorPath = null;
    public $ignoreNull = true;

    public function getRequiredOptions()
    {
        return array('fields');
    }

    /**
     * The validator must be defined as a service with this name.
     *
     * @return string
     */
    public function validatedBy()
    {
        return $this-&gt;service;
    }

    /**
     * {@inheritDoc}
     */
    public function getTargets()
    {
        return self::CLASS_CONSTRAINT;
    }

    public function getDefaultOption()
    {
        return 'fields';
    }
}</pre><p>Lo primero que salta a la vista, es que podemos añadirle atributos públicos. Estos atributos contienen información sobre la configuración que usaremos en el Validator y los podemos sobrescribir cuando instanciamos el <a title="UniqueEntity" href="http://symfony.com/doc/current/reference/constraints/UniqueEntity.html">Constraint</a>:</p><pre class="crayon-plain-tag">namespace Acme\AdministrationBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;

/**
 * @ORM\Entity
 * @UniqueEntity(
 *     fields={"host", "port"},
 *     errorPath="port",
 *     message="This port is already in use on that host."
 * )
 */
class Service
{
    /**
     * @ORM\ManyToOne(targetEntity="Host")
     */
    public $host;

    /**
     * @ORM\Column(type="integer")
     */
    public $port;
}</pre><p>Otra cosa importante que podemos configurar es el <strong>target </strong>con el método <em>getTargets</em>, la Constraint puede afectar a una propiedad, un método o una clase entera, en el caso de la propiedad, a la hora de validar sólo tendremos acceso al valor que contiene. Si indicamos, como en el caso de UniqueEntity que el Target es la clase, tendremos acceso a una instancia de esa clase en el Validator, por lo que podemos acceder a los métodos o atributos públicos que tenga:</p><pre class="crayon-plain-tag">public function getTargets()
{
    return self::CLASS_CONSTRAINT;
}</pre><p>Por otra parte podemos indicar qué campos son los requeridos:</p><pre class="crayon-plain-tag">public function getRequiredOptions()
{
    return array('fields');
}</pre><p>Y cuál es el campo por defecto si sólo nos envían un parámetro de configuración:</p><pre class="crayon-plain-tag">public function getDefaultOption()
{
    return 'fields';
}</pre><p>Por lo que si añadimos el Constraint así:</p><pre class="crayon-plain-tag">/**
 * @ORM\Entity
 * @UniqueEntity("email")
 */
class Author</pre><p>Es como si lo indicáramos así:</p><pre class="crayon-plain-tag">/**
 * @ORM\Entity
 * @UniqueEntity(fields={"email"})
 */
class Author</pre><p>También podemos indicar el groups como en todas las constraints y finalmente tenemos el método <em>validatedBy</em> que indica cuál va a ser el Validator asociado. Por defecto es una clase que se llama igual que el Constraint + Validator:</p><pre class="crayon-plain-tag">public function validatedBy()
{
    return get_class($this).'Validator';
}</pre><p>Cuando creamos un Validator al que le debemos inyectar algunas dependencias, tendremos que declarar el Validator como servicio y tendremos que añadirle el tag <em>validator.constraint_validator</em> y un alias que será el mismo nombre que el método validatedBy deberá devolver, que es justo que lo hace UniqueEntity.</p><pre class="crayon-plain-tag">&lt;service id="doctrine.orm.validator.unique" class="%doctrine.orm.validator.unique.class%"&gt;
    &lt;tag name="validator.constraint_validator" alias="doctrine.orm.validator.unique" /&gt;
    &lt;argument type="service" id="doctrine" /&gt;
&lt;/service&gt;</pre><p>En la documentación oficial podéis encontrar <a title="Custom Validator" href="http://symfony.com/doc/current/cookbook/validation/custom_constraint.html">cómo crear un Custom Validator</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://showmethecode.es/php/symfony/symfony2-constraints/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Doctrine2: Paginator</title>
		<link>http://showmethecode.es/php/doctrine2/doctrine2-paginator/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=doctrine2-paginator</link>
		<comments>http://showmethecode.es/php/doctrine2/doctrine2-paginator/#comments</comments>
		<pubDate>Mon, 03 Mar 2014 08:00:41 +0000</pubDate>
		<dc:creator><![CDATA[Fran Moreno]]></dc:creator>
				<category><![CDATA[Doctrine2]]></category>
		<category><![CDATA[Paginator]]></category>

		<guid isPermaLink="false">http://showmethecode.es/?p=2084</guid>
		<description><![CDATA[A partir de la versión 2.2 de Doctrine, podemos encontrarnos la clase Paginator para paginar consultas DQL. Esta clase nos va a permitir, principalmente, paginar las consultas DQL en las que usamos fetch-join. Las consultas con fetch-join son aquellas que además de hacer el join, en el resultado devolvemos la entidad relacionada, es decir: [crayon-5bf4486fb31fe538686830/]]]></description>
				<content:encoded><![CDATA[<p>A partir de la versión 2.2 de Doctrine, podemos encontrarnos la clase <a title="Paginator" href="https://github.com/doctrine/doctrine2/blob/master/lib/Doctrine/ORM/Tools/Pagination/Paginator.php">Paginator</a> para paginar consultas DQL. Esta clase nos va a permitir, principalmente, paginar las consultas DQL en las que usamos fetch-join.<span id="more-2084"></span></p>
<p>Las <a title="fetch-join" href="http://docs.doctrine-project.org/en/latest/reference/dql-doctrine-query-language.html#joins">consultas con fetch-join</a> son aquellas que además de hacer el join, en el resultado devolvemos la entidad relacionada, es decir:</p><pre class="crayon-plain-tag">$query = $em-&gt;createQuery("SELECT u, a FROM User u JOIN u.address a WHERE a.city = 'Berlin'");
$users = $query-&gt;getResult();</pre><p>Con esto hacemos que con sólo una consulta, podamos recuperamos los usuarios y sus direcciones sin tener que hacer consultas extra. El problema está cuando queremos <a title="limit results" href="http://docs.doctrine-project.org/en/latest/reference/dql-doctrine-query-language.html#first-and-max-result-items-dql-query-only">limitar el número de resultados</a>:</p>
<blockquote><p>If your query contains a fetch-joined collection specifying the result limit methods are not working as you would expect. Set Max Results restricts the number of database result rows, however in the case of fetch-joined collections one root entity might appear in many rows, effectively hydrating less than the specified number of results.</p></blockquote>
<p>Para esto, podemos usar la clase Paginator como indica <a title="Doctrine Paginator" href="http://doctrine-orm.readthedocs.org/en/latest/tutorials/pagination.html">la documentación</a>:</p><pre class="crayon-plain-tag">use Doctrine\ORM\Tools\Pagination\Paginator;

$dql = "SELECT p, c FROM BlogPost p JOIN p.comments c";
$query = $entityManager-&gt;createQuery($dql)
                       -&gt;setFirstResult(0)
                       -&gt;setMaxResults(100);

$paginator = new Paginator($query, $fetchJoinCollection = true);

$c = count($paginator);
foreach ($paginator as $post) {
    echo $post-&gt;getHeadline() . "\n";
}</pre><p>También hay veces que en proyectos siempre vamos a paginar cosas como la que acabamos de ver, para este tipo de cosas no hace falta usar bundles que paginen por cualquier cosa. Con la clase Paginator podemos <a title="paginate results Paginator" href="http://stackoverflow.com/questions/15906051/doctrine2-paginator-getting-total-results">hacer algo así</a>:</p><pre class="crayon-plain-tag">use Doctrine\ORM\Tools\Pagination\Paginator;

function paginate($dql, $pageSize = 10, $currentPage = 1)
{
    $paginator = new Paginator($dql);

    $paginator
        -&gt;getQuery()
        -&gt;setFirstResult($pageSize * ($currentPage - 1)) // set the offset
        -&gt;setMaxResults($pageSize); // set the limit

    return $paginator;
}</pre><p>Y si queremos ver el número total de items y de páginas:</p><pre class="crayon-plain-tag">$totalItems = count($paginator);
$pagesCount = ceil($totalItems / $paginator-&gt;getMaxResults());</pre><p></p>
]]></content:encoded>
			<wfw:commentRss>http://showmethecode.es/php/doctrine2/doctrine2-paginator/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Symfony2: Componente Finder para buscar ficheros y directorios</title>
		<link>http://showmethecode.es/php/symfony2-componente-finder-para-buscar-ficheros-y-directorios/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=symfony2-componente-finder-para-buscar-ficheros-y-directorios</link>
		<comments>http://showmethecode.es/php/symfony2-componente-finder-para-buscar-ficheros-y-directorios/#comments</comments>
		<pubDate>Mon, 24 Feb 2014 08:00:23 +0000</pubDate>
		<dc:creator><![CDATA[Fran Moreno]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Finder]]></category>
		<category><![CDATA[Symfony2]]></category>

		<guid isPermaLink="false">http://showmethecode.es/?p=889</guid>
		<description><![CDATA[Finder es uno de los componentes que forman Symfony2, este componente nos permite buscar ficheros y directorios a través de una interfaz muy intuitiva. El otro día vi un tweet en el que se indicaba cómo listar los ficheros de un directorio en PHP plano y de ahí este artículo. Hay mucha gente que usa]]></description>
				<content:encoded><![CDATA[<p>Finder es uno de los componentes que forman Symfony2, este componente nos permite <strong>buscar ficheros y directorios a través de una interfaz muy intuitiva</strong>. El otro día vi un tweet en el que se indicaba cómo listar los ficheros de un directorio en PHP plano y de ahí este artículo.<span id="more-889"></span></p>
<p>Hay mucha gente que usa el framework Symfony2, pero que desconoce una de las cosas más <strong>importantes</strong> que tiene y eso son los <strong>componentes</strong> que podemos usar por separado. No hace falta que usemos todo el framework cuando a veces sólo nos hace falta cierta funcionalidad que podemos cubrir con alguno o varios componentes.</p>
<p>En este caso vamos a ver unos ejemplos con <a title="Finder" href="http://symfony.com/doc/current/components/finder.html">el componente Finder</a>. Este componente a mí particularmente me gusta mucho por la <strong>interfaz</strong> tan <strong>intuitiva</strong> que tiene.</p>
<p>El ejemplo que vi era listar los ficheros en un directorio recursivamente, ahora mismo no recuerdo cuántas líneas tenía, pero seguramente serían más de 25 líneas de código. Con Finder si queremos listar los ficheros se haría así:</p><pre class="crayon-plain-tag">use Symfony\Component\Finder\Finder;

$path = __DIR__;

$finder = new Finder();
$finder-&gt;files()-&gt;in($ruta);

foreach ($finder as $file) {
    print $file-&gt;getRelativePathname() . "\n";
}</pre><p>Este era el ejemplo más sencillo, pero Finder nos proporciona una gran cantidad de métodos para configurar la búsqueda, como este ejemplo sacado de la documentación en el que podemos ver todo el potencial:</p><pre class="crayon-plain-tag">use Symfony\Component\Finder\Finder;

$s3 = new \Zend_Service_Amazon_S3($key, $secret);
$s3-&gt;registerStreamWrapper("s3");

$finder = new Finder();
$finder-&gt;name('photos*')-&gt;size('&lt; 100K')-&gt;date('since 1 hour ago');
foreach ($finder-&gt;in('s3://bucket-name') as $file) {
    // ... do something

    print $file-&gt;getFilename()."\n";
}</pre><p>Como podemos ver, en vez de buscar en local, está buscando en Amazon S3 y lo que está buscando son ficheros cuyo nombre empiece por <em>photos</em>, con un tamaño menor a 100K y que la fecha de modificación sea desde hace 1 hora.</p>
<p>Hacer todo esto en PHP plano nos llevaría mucho tiempo y con el componente Finder lo podemos resolver de una forma muy elegante y en muy poco tiempo.</p>
<p>Para acabar vamos a ver unos cuantos ejemplos más sacados de la documentación.</p><pre class="crayon-plain-tag">$finder-&gt;in('src/Symfony/*/*/Resources');

$finder-&gt;in(__DIR__)-&gt;exclude('bin');

$finder-&gt;ignoreUnreadableDirs()-&gt;in(__DIR__);

$finder-&gt;in('ftp://example.com/pub/');

$finder-&gt;sortByType();</pre><p>Lo mejor de estos ejemplos es que no hace falta explicarlos porque se leen perfectamente.</p>
<p>Échale un vistazo a <a title="Finder" href="http://symfony.com/doc/current/components/finder.html">la documentación</a> para ver todas las posibilidades.</p>
]]></content:encoded>
			<wfw:commentRss>http://showmethecode.es/php/symfony2-componente-finder-para-buscar-ficheros-y-directorios/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symfony2: Internacionalización usando el subdominio</title>
		<link>http://showmethecode.es/php/symfony/symfony2-internacionalizacion-usando-el-subdominio/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=symfony2-internacionalizacion-usando-el-subdominio</link>
		<comments>http://showmethecode.es/php/symfony/symfony2-internacionalizacion-usando-el-subdominio/#comments</comments>
		<pubDate>Mon, 17 Feb 2014 08:00:56 +0000</pubDate>
		<dc:creator><![CDATA[Fran Moreno]]></dc:creator>
				<category><![CDATA[Symfony]]></category>
		<category><![CDATA[Routing]]></category>
		<category><![CDATA[Symfony2]]></category>

		<guid isPermaLink="false">http://showmethecode.es/?p=2066</guid>
		<description><![CDATA[Hay muchas páginas internacionalizadas en las que el idioma se indica en el subdominio, como por ejemplo Facebook o Yahoo. A partir de la versión 2.2 de Symfony, hacer esto es muy sencillo, ya que podemos indicar el host en la definición de la ruta. [crayon-5bf4486fc5fe6916256409/] En este caso, se recomienda añadir otro placeholder para]]></description>
				<content:encoded><![CDATA[<p>Hay muchas páginas internacionalizadas en las que el idioma se indica en el subdominio, como por ejemplo Facebook o Yahoo. A partir de la versión 2.2 de Symfony, hacer esto es muy sencillo, ya que podemos indicar el host en la definición de la ruta.<span id="more-2066"></span></p><pre class="crayon-plain-tag">homepage:
    path:     /
    host:     "{_locale}.example.com"
    defaults:
        _controller: AcmeDemoBundle:Main:homepage
    requirements:
        _locale: en|fr|de</pre><p>En este caso, se recomienda añadir otro <em>placeholder</em> para el dominio:<span style="background-color: #cce4f5; font-family: 'Courier 10 Pitch', Courier, monospace; font-size: 11px; line-height: 18px;"><br />
</span></p><pre class="crayon-plain-tag">homepage:
    path:     /
    host:     "{_locale}.{domain}"
    defaults:
        _controller: AcmeDemoBundle:Main:homepage
        domain: %domain%
    requirements:
        _locale: %locales%
        domain: "%domain%"</pre><p>Ahora sólo nos queda definir el parámetro <strong>domain</strong> (y <strong>locales</strong>) en nuestra configuración. Esto nos va a permitir cuando estamos trabajando en local definir el dominio por ejemplo a <em>example.local</em> y en producción tenerlo como <em>example.com</em>.</p>
<p>También <a title="import host routing" href="http://symfony.com/doc/current/components/routing/hostname_pattern.html#using-host-matching-of-imported-routes">podemos indicar el host cuando importamos la ruta</a>:</p><pre class="crayon-plain-tag"># app/config/routing.yml
acme_hello:
    resource: "@AcmeHelloBundle/Resources/config/routing.yml"
    host:     "{_locale}.{domain}"
    defaults:
        domain: %domain%
    requirements:
        _locale: %locales%
        domain: "%domain%"</pre><p>Una alternativa a esto sería crear un Listener que nada más llegar la petición, obtuviera el subdominio y desde ahí configuraríamos el locale y lo que nos hiciera falta.</p>
]]></content:encoded>
			<wfw:commentRss>http://showmethecode.es/php/symfony/symfony2-internacionalizacion-usando-el-subdominio/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
