Symfony2 Community Series: Adding variables to twig output

The rest of this blog post was written by @mablea.

Yesterday @userfriendly posted a interesting Question on Freenode/#symofony:

He asked about how to add class attributes to the `option` Tags of a EntityType.php form field. After looking at the code we found out that this is not possible with the native behavior of the type EntityType or with any `select` field.

Then I had the idea to work the variables I can access without making changes to the Symfony2 Modules. Here is the solution:

I introduced two new methods to the Entity class.

    <?php
    /* /src/Acme/DemoBundle/Entity/Category.php */
 
    /*  (...) */
 
    /**
     * @return boolean
     */
    public function isTopLevel()
    {
        return $this->getParent() == null ? true : false;
    }
 
 
    /**
     * return array
     */
    public function getCategoryTypeTitle()
    {
        return array('isTopLevel' => $this->isTopLevel(), 'label' => $this->__toString());
    }

Since the default Twig template for the rendering asumes the given label is a `string` we need to introduce a new FormType called `CategoryType.php` in this case.

    <?php
    // /src/Acme/DemoBundle/Form/CategoryType.php
 
    namespace Acme\DemoBundle\Form\Type;
 
    use Doctrine\Common\Persistence\ObjectManager;
    use Symfony\Component\Form\AbstractType;
    use Symfony\Bridge\Doctrine\Form\ChoiceList\ORMQueryBuilderLoader;
 
    class CategoryType extends AbstractType
    {
        public function getName()
        {
            return 'category';
        }
 
        public function getParent()
        {
            return 'entity';
        }
    }

Next, we register the new form type in our `config.yml`:

This step is optional, but if we want to call our new FormType in string form, like the built-in ones (´’entity’, ‘coiche’, .. ´), we need it.

    # /app/config/config.yml
    services:
        form.type.category:
            class: Acme\DemoBundle\Form\Type\CategoryType
            tags:
                - { name: form.type, alias: category }

Now we overwrite the twig template for our Form Type using the ´fields.html.twig´:

    {# /src/Acme/DemoBundle/Resources/views/Form/fields.html.twig #}
    
    {% block category_choice_widget_options %}
    {% spaceless %}
    {% for index, choice in options %}
    {% if _form_is_choice_group(choice) %}
    <optgroup label="{{ index|trans({}, translation_domain) }}">
        {% for nested_choice in choice %}
        <option value="{{ nested_choice.value }}"{% if _form_is_choice_selected(form, nested_choice) %} selected="selected"{% endif %}>{{ nested_choice.label|trans({}, translation_domain) }}</option>
        {% endfor %}
    </optgroup>
    {% else %}
    <option {% if choice.label.isTopLevel %}class="isTopLevel"{% endif %} value="{{ choice.value }}"{% if _form_is_choice_selected(form, choice) %} selected="selected"{% endif %}>{{ choice.label.label|trans({}, translation_domain) }}</option>
    {% endif %}
    {% endfor %}
    {% endspaceless %}
    {% endblock category_choice_widget_options %}

The important part is overwritten in the block above. Look at the ´\

    {# /src/Acme/DemoBundle/Resources/views/Form/fields.html.twig #}

    {% block category_choice_widget_collapsed %}
    {% spaceless %}
    <select {{ block('widget_attributes') }}{% if multiple %} multiple="multiple"{% endif %}>
        {% if empty_value is not none %}
        <option value="">{{ empty_value|trans({}, translation_domain) }}</option>
        {% endif %}
        {% if preferred_choices|length > 0 %}
        {% set options = preferred_choices %}
        {{ block('choice_widget_options') }}
        {% if choices|length > 0 and separator is not none %}
        <option disabled="disabled">{{ separator }}</option>
        {% endif %}
        {% endif %}
        {% set options = choices %}
        {{ block('category_choice_widget_options') }}
    </select>
    {% endspaceless %}
    {% endblock category_choice_widget_collapsed %}
 
    {% block category_widget %}
    {% spaceless %}
    {% if expanded %}
    <ul {{ block('widget_container_attributes') }}>
        {% for child in form %}
        <li>
            {{ form_widget(child) }}
            {{ form_label(child) }}
        </li>
        {% endfor %}
    </ul>
    {% else %}
    {# just let the choice widget render the select tag #}
    {{ block('category_choice_widget_collapsed') }}
    {% endif %}
    {% endspaceless %}
    {% endblock %}

Last step is to tell the form component where our template is on the filesystem:

    # /app/config/config.yml
    
    twig:
        # ...
        form:
            resources:
                - 'AcmeDemoBundle:Form:fields.html.twig'

Now, in our `buildForm()` method we can use the new CategoryType like this:

        // add your custom field
        $builder->add('category', 'category', array(
            'class' => 'AcmeDemoBundle:Category',
            'property' => 'CategoryTypeTitle'
        ));

The `property` option points to the method used to get the label. But we return our array holding the label and a boolean value (`isTopLevel`). This works without errors so far I can say. But I didn’t make any unit tests our deep analysis on it. Only tested with dev-master (v2.1x)!

This method is hackish. But until version 2.2 Symfony2 will not support this feature by default. At the moment there is a feature freeze on Form Component until the version 2.1 of Symfony2 is out.

You could also use this method to add ´data-´ attributes to your choices and read them out with Jquery on the client side.

I hope you like thi sone shared with you in agreement with its author.
Symfony2 community FTW!

Test Symfony2 GUI Apps in Windows7 with IE8 and IE9 The Right Way!

Ever wanted to browse your symfony2 apps from the point of view of those old stiff corporates that don’t know how to install better programs?
Fasten your seat belts!

Update: The right way ended up being https://github.com/xdissent/ievms (thanks @helios_ag)

Go first and download the legal images from this link: http://www.microsoft.com/en-us/download/details.aspx?id=11575
To aid you in your selection just download all 3 by 3 because i am sure you will have corruption problems. If the exe fails when you run it on your ubuntu just remove the files and download the again and again until you get them to work. Don’t be discouraged just try it and defeat it.

Once you grab your images and run the exe for each of the IE7, IE8, IE9 that you want to install (shame on you if IE6), you should get two files for each set, namely a Win7_IE8.vmc and a Win7_IE8.vhd for the IE8 version for instance. I will assume you have installed the latest virtualbox software from the ubuntu software center in your ubuntu. Run that and create a box and init the box with your already existent disk image, yes the vhd file.

After your box is all set and running you would ask yourself how to see my symfony2 app from the virtual box guest browser (yes this is the windows 7 with IE8 or IE9, etc). First follow and make sure the pinging works between the guest browsing the app and the host serving the app through apache or other.
Troubleshot tips, pinging from guest box to the host and from host to guest box:

// from guest windows box
ping 192.168.1.34 // IP address of the ubuntu host
// from ubuntu box
ping 192.168.1.36 // IP address of the virtual box

Step1: Edit your hosts on your windows box to include an entry pointing to your Ubuntu’s IP address (mine is 192.168.1.34) the one running apache and serving the symfony2 app:

// 127.0.0.1   localhost
129.168.1.34   myapp.local

Step2: Set your virtualbox network settings of the windows guest to Bridge and set it to allow on the select box to ALL VMS and what not.
Step3: Drop your defense iptables to allow for the guest to access pages served by the host:

// this works:
~ sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
// thanks to @helios_ag who recommended these:
~ ufw allow http
~ ufw allow 80

Then open your browser on your windows guest virtual box and type:

http://myapp.local/app_dev.php

And of course you will get the one line warning. But from here on you know what to do if you are a symfony2 guy.
If you get errors make sure you troubleshoot and drop your firewalls allowing for the access with iptable settings as above.

I hope this has helped you. I thank God for having such good friends in the community.
Also I make sure to mention that all of this is undeserved because I cannot repay God’s grace.
Lastly, if you would like to see me at SymfonyLive in San Francisco and would like to contribute towards my air ticket 1800$ ($100 already raised) please follow this link: http://bit.ly/9xbyzM. The flight is very expensive but I am so eager to go and thanks for all that are already supporting me, we will have so much learning there. Looking forward to meet the community you!

Getting your Symfony2 Team On Board With Git Line Endings!

Lately I ran into this help page from github here.
The main problem that this solves and the one I ran into was that I made some modifications to a file in a git repository and to my surprise I was met by an ugly scenario when doing `git diff` showing strange characters `^M` which were showing red and ugly:

I tried in vain to get rid of these windows format line endings. Then was redirected to the link above but just initially set my .gitconfig to no effect.
In order to solve this there were two options: (1) waiting until project manager would make a transition from an unclean repo to a reformatted one, or (2) just cope with it and either run a nice utility called `dos2unix` (you can install it by `sudo apt-get install dos2unix on ubuntu) to filter those characters, stash my changes, then commit the whole file changes after the dos2unix command, yes this command changes all the file, then apply my stashed changes, then commit again. The latter solution is not very nice as there is an ugly bump in history as to who change what in the file. So I just went ahead and made my changes and accept for one only time to see those weird characters on my `git diff`. The reason why those characters were there was that for that particular repository on some version at some point the file got edited in Microsoft products by someone using Windows OS.

The morale of the story is that in order to avoid these problems with strange end of line characters we could just make our project totally independent of what the OS of the team’s developers use. The `.gitattributes` file accomplishes this by telling git what to do or how to behave when checking out these files. Following is a `.gitattributes` I wrote in order to accomplish this for a symfony2 generic project. It is my hope that people would contribute to it and would improve it. Here is the https://github.com/cordoval/symfony2-gitattributes to fork and PR and following is a excerpt:

# Set default behaviour, in case users don't have core.autocrlf set.
* text=auto
 
# Explicitly declare text files we want to always be normalized and converted 
# to native line endings on checkout.
*.php text
*.txt text
*.ini text
//...
*.js text
*.css text
*.cache text
*.meta text
*.phar text
app/console text
console text
vendors text
.gitignore text
// ...
 
# Denote all files that are truly binary and should not be modified.
*.png binary
*.gif binary
*.jpg binary
*.db binary
*.jar binary
*.ico binary
.gitkeep binary

It has inline comments that explain what each section does. Please from now on make sure you include this file in your symfony2 project.
If you liked this and want to support me going to symfonyLive in San Francisco please donate.

Interview To PHPPeru

Republish from source:

En la última edición del programa ‘Web Inc.’, que conducen Germán Martinez y Antonio Ognio por La MulaTV, estuvimos con Luis Córdova, experto desarrollador que lidera la comunidad PHP Perú.

Desde mediados de los noventas, PHP es una de las tecnologías más populares para la construcción de sitios web del lado del servidor.

La comunidad PHP Perú cuenta actualmente con más de 50 miembros que participan de reuniones presenciales y virtuales. Sus integrantes discuten, no solo de PHP, sino del conjunto de otras habilidades esenciales para los desarrolladores tales como: patrones de diseño, testing, control de versiones, paquetes entre otros.

Luis Córdova señaló que, entre las opciones de los programadores, también está la participación en comunidad, ayudando a otros y aprendiendo de los que saben más que uno. “Existe la necesidad de que el peruano se abra y participe con el exterior. El desarrollo va de la mano con la comunidad”, afirmó.

Posteriormente se conversó sobre Symfony 2, un framework full stack para PHP de última generación. Este sofware se construye sobre la base de un gran número de componentes, que están siendo usados como piezas fundacionales por los sistemas de manejo de contenido (SMC) más recientes como Drupal 8. Esto facilita la inter- operatividad con otras soluciones y el re-uso del código.

Finalmente, Córdova animó a que los programadores entren en la comunidad para aprender a contribuir con código a proyectos como Symfony 2 y otros. De esta manera serían partícipes de una comunidad global de programadores a través de internet y en eventos especializados. La comunidad pretende la participación enfocada el desarrollo: “Mejor hacer las herramientas que usarlas. Es importante la participación en development más que modificar o tomar algo ya hecho”, concretó .

Para más información:

Web: www.phpperu.org
Twitter: @php_peru
Facebook: http://www.facebook.com/pages/PHP-Per%C3%BA/92445137292
Grupo de google: https://groups.google.com/forum/?fromgroups#!forum/phpperu

I give thanks to the Lord for the undeserved grace and opportunity to get to talk on php and the community here.
Thanks for all the friends that make this possible.

Kiss Your Travis-CI Good-Bye with Symfony2 Vagrant

I have problems with vagrant right from the get go. The idea is to setup a travis like environment to pre-test tests to be send to travis.
The problem I am trying to overcome appears when we have too elaborated settings in travis and experience too long wait time that make the whole testing experience very tedious.

Right from the get go i ran into a wrong assumption. I assume that i had installed vagrant just because rvm and ruby 1.9.2 was present on my system. The vagrant site tells you to download the package and run it with standard procedures. However ubuntu has the right version on its channels if you are using precise. So just use that and don’t try to either download the package or try to install it on your rvm or gems. Yes sorry ruby got me frustrated this morning. I don’t say it sucks, I say it is a mess!

Then next step is to do:

~ git clone git://github.com/cordoval/vagrant-php-dev-box.git
~ cd vagrant-php-dev-box
~ vagrant box add precise64 http://files.vagrantup.com/precise64.box
~ #vagrant init precise64 (this will tell you there is an already vagrant file created so just move on)
~ vagrant up (first time failed me because of port collisions)

So if port collisions check it with (thanks @boonkerz):

~ netstat -lnptu
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:27017           0.0.0.0:*               LISTEN      -               
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      -

Then enter the Vagrantfile on the root vagrant dev box project directory and change the numbers (27017 before):

  config.vm.forward_port 80, 1234

Then rerun `vagrant up` and there you go.

If you forget or need some special things to have either composer or your project dependencies to work well then you can proceed to do `vagrant ssh` and install inside the needed dependencies, for example:

~ sudo apt-get install php5-curl

If after you run `vagrant up` you get something like the following:

~ vagrant up
[default] Importing base box 'precise64'...
[default] The guest additions on this VM do not match the install version of
VirtualBox! This may cause things such as forwarded ports, shared
folders, and more to not work properly. If any of those things fail on
this machine, please update the guest additions and repackage the
box.
 
Guest Additions Version: 4.1.16
VirtualBox Version: 4.1.18
[default] Matching MAC address for NAT networking...
[default] Clearing any previously set forwarded ports...
[default] Forwarding ports...
[default] -- 22 => 2222 (adapter 1)
[default] -- 80 => 1234 (adapter 1)
[default] -- 27017 => 1235 (adapter 1)
[default] Creating shared folders metadata...
[default] Clearing any previously set network interfaces...
[default] Running any VM customizations...
[default] Booting VM...
[default] Waiting for VM to boot. This can take a few minutes.
[default] VM booted and ready for use!
[default] Mounting shared folders...
[default] -- v-root: /vagrant
[default] -- manifests: /tmp/vagrant-puppet/manifests
[default] Running provisioner: Vagrant::Provisioners::Puppet...
[default] Running Puppet with /tmp/vagrant-puppet/manifests/default.pp...
stdin: is not a tty
No LSB modules are available.
warning: Could not retrieve fact fqdn
notice: /Stage[main]/Development/Exec[apt-get update]/returns: executed successfully
notice: /Stage[main]/Php5/Package[php5-mysql]/ensure: ensure changed 'purged' to 'present'
notice: /Stage[main]/Development/Package[git]/ensure: created
notice: /Stage[main]/Php5/Package[php-apc]/ensure: ensure changed 'purged' to 'present'
notice: /Stage[main]/Php5/File[/etc/php5/conf.d/custom.ini]/ensure: defined content as '{md5}d918da65f01e420a256bd5721848f8a6'
notice: /Stage[main]/Php5/Package[php5-xdebug]/ensure: ensure changed 'purged' to 'present'
notice: /Stage[main]/Php5/Package[php5-sqlite]/ensure: ensure changed 'purged' to 'present'
notice: /Stage[main]/Development/Package[php-pear]/ensure: ensure changed 'purged' to 'present'
notice: /Stage[main]/Development/Package[curl]/ensure: ensure changed 'purged' to 'present'
notice: /Stage[main]/Php5/Package[php5-cgi]/ensure: ensure changed 'purged' to 'present'
notice: /Stage[main]/Development/Exec[set pear autodiscover]/returns: executed successfully
notice: /Stage[main]/Development/Exec[install phpunit]/returns: executed successfully
notice: /Stage[main]/Symfony-standard/Exec[run composer for symfony when composer is used]/returns: executed successfully
notice: /Stage[main]/Symfony-standard/Exec[install composer for symfony when needed]/returns: executed successfully
notice: /Stage[main]/Php5/Package[php5-intl]/ensure: ensure changed 'purged' to 'present'
notice: Finished catalog run in 494.53 seconds

Then even the virtual box was created you need to update your virtualbox guest additions with this script (thanks @debo).

# Installing the virtualbox guest additions
sudo apt-get -y install linux-headers-$(uname -r) build-essential
sudo apt-get -y install dkms
VBOX_VERSION=4.1.18 # this is the latest version at the time of the blog post
cd /tmp
wget http://download.virtualbox.org/virtualbox/$VBOX_VERSION/VBoxGuestAdditions_$VBOX_VERSION.iso
sudo mount -o loop VBoxGuestAdditions_$VBOX_VERSION.iso /mnt
sudo sh /mnt/VBoxLinuxAdditions.run
sudo umount /mnt

After this step you want to exit the virtualbox and then do a `virtual reload`. Be mindful you may need to reinstall some things but your virtualbox is certain to have Guest Additions already upgraded to 4.1.18. The Guest Additions step is a MUST because of this 3 day nightmare. Here is another link that can serve the explanation and also be useful. But the script is enough to make it work.

At this point I ran into this blog post: http://www.adayinthelifeof.nl/2012/06/29/using-vagrant-and-puppet-to-setup-your-symfony2-environment/ so the idea now is to add the user-group www-data to vagrant as in the blog post.

Another note I can make is regarding the time outs from composer within a vagrant slow connection box. Here is the link and the command:

vagrant@precise64:/vagrant/www/KnpBundles$ COMPOSER_PROCESS_TIMEOUT=4000 php composer.phar install --dev -v

http://www.ubuntuka.com/add-user-to-existing-group-ubuntu/
http://serverfault.com/questions/398414/vagrant-set-default-share-permissions