Fedora 17 & Windows 7 dual-boot on DELL XPS 15 (L521x)

Yesterday I got my new DELL XPS 15. The first thing I wanted to do was to remove the bloated OEM system and to install Fedora 17 and a fresh Windows 7 for occasional gaming.
My XPS has a 750GB HDD and a 32GB SSD which is used as a cache by default. The plan was to use the SSD as a standalone hard drive containing the system-relevant linux partitions and to put the /home partition and Windows on the HDD. I can say that I’m impressed by the speed of my Fedora system now and can recommend this configuration. However, I had to overcome some unexpected obstacles, so here are the steps which should get you a working dual-boot system without much googling and swearing :)

1. Create the recovery medium
You have to decide whether it is neccessary or whether it makes sense to create the recovery media using DELL’s DataSafe application. Since DELL isn’t shipping any installation discs with some of it’s notebooks anymore this might be a good idea. On the other hand you can get a new Windows installation disc from the internet.

2. Change SATA Operation Mode
By default the SSD is used as a cache for the HDD. You can change this behaviour in the BIOS of your notebook. Just start the notebook and press F2 during boot. You can set the SATA Operation Mode from Intel’s caching strategy to AHCI which will allow you to use the SSD as a ordinary hard drive.

3. Flush hard drive metadata
The hard drives are configured with some crazy kind of RAID (maybe this has to do with the caching). Unless you remove the metadata from the hard drives you won’t be able to change the partition tables properly using Gparted.

In order to remove the metadata you have to boot the Fedora 17 Live CD (or Knoppix or something else), go to the terminal and execute:

su
dmraid -r -E /dev/sda
dmraid -r -E /dev/sdb

4. Create a new partition for Windows
Now you can use GParted to create a new partition for Windows 7. The Live CD doesn’t include Gparted and Wifi isn’t working by default, so you have to plug in an Ethernet cable and install Gparted:

su
yum install gparted

Then you can start it:

gparted

Go to “GParted > Devices > /dev/sda” (which is the HDD) and then choose “Device > Create partition table” and use the default settings. Now you can create a new partition on the HDD by clicking on “Parition > New”. Place the partition at the beginning of the harddrive, choose the desired size (I chose 200GB) and set the file system to NTFS.

Now you have prepared the notebook for the installation of Windows 7.

5. Install Windows 7
You can install Windows 7 now. You can either use a DVD if you have one or burn an image which you can get from DigitalRiver (download links). Just insert the boot media and restart the XPS. The installation steps should be self-explanatory. Choose the NTFS partition as the installation target.

6. Install Fedora 17
After you have installed Windows you can install Fedora. Therefore you have to insert the Fedora 16 Live CD (or the installation DVD) and reboot the system. During the installation you will be asked how you want the partitions to be structured. You can let Fedora try to “Use Free Space” and click “Next” to get an idea on which partition sizes Fedora decided to be appropriate. In my case the layout wasn’t ideal so I chose to create a custom layout:

7. Install bootloader
In my case GRUB hadn’t been installed properly so I had to boot the Fedora 17 DVD!, choose “Troubleshooting” and then the rescue system. From there I could chroot my Fedora system on the hard drive and reinstall GRUB to sda:

chroot /mnt/sysimage
grub2-install /dev/sda

8. Update Fedora
GRUB should now be available at startup and you should be able to start Fedora. Wifi won’t work by default, but after updating the whole system over Ethernet (from kernel 3.2.* to 3.5.*) there were no problems anymore.

9. Enjoy!
Now you can enjoy a lightning-SSD-fast Fedora and try to find some spare time to play some Windows games ;)

Read More

Testing HTTP interactions with Symfony’s Process component and PHP 5.4

Today I wrote a class called “HttpLoader” that downloads an external web page. Later on it will be used for pingback handling. My problem was though that it’s not easy to test such a class. I could have downloaded http://example.org or something like this in my unit test, but I didn’t think that this would be the best solution.
After a while I thought: “Well, there’s a built-in webserver in PHP 5.4! So why don’t use it for my tests?”. Additionaly I knew about the Process component of Symfony and ready was my abstract test class:

use PHPUnit_Framework_TestCase;
use Symfony\Component\Process\Process;
 
/**
 * Abstract TestCase that allows to start the built-in PHP server
 * with a custom router script.
 */
abstract class AbstractHttpTest extends PHPUnit_Framework_TestCase
{
    /**
     * The default port the server should listen on.
     */
    const TEST_PORT = 8181;
 
    /**
     * The server process.
     *
     * @var Process
     */
    private $process = null;
 
    /**
     * The port of the current server process.
     *
     * @var int
     */
     private $port;
 
    /**
     * Sets up a test and checks if the requirements for the server are met.
     */
    public function setUp()
    {
        if (!version_compare(PHP_VERSION, '5.4.0', '>='))
        {
            $this->markTestSkipped("PHP 5.4 is neccessary to use the test server");
        }
 
        if (!class_exists('Symfony\\Component\\Process\\Process')) {
            $this->markTestSkipped("Symfony Process library is not available");
        }
    }
 
    /**
     * Starts the test server.
     *
     * @param string $router Router script.
     * @param int $port Server port.
     */
    public function startServer($router, $port = 0)
    {
        if ($this->process) {
            $this->process->stop();
        }
 
        $this->port = $port ? $port : static::TEST_PORT;
        $command = sprintf(PHP_BINARY . ' -S 127.0.0.1:%d %s', $this->port, $router);
 
        $this->process = new Process($command);
        $this->process->start();
 
        // Give the server some time to start
        $now = time();
        while ($this->process->isRunning() && time() - $now < 2) {
            $handle = @fsockopen('127.0.0.1', $this->port);
            if ($handle !== false) {
                fclose($handle);
                return;
            }
        }
 
        $this->fail('Could not start webserver');
    }
 
    /**
     * Stops the server.
     */
    public function stopServer()
    {
        if ($this->process) {
            $this->process->stop();
        }
    }
 
    /**
     * Kills the server gracefully.
     */
    public function __destruct()
    {
        $this->stopServer();
    }
 
    public function createUrl($path)
    {
        return sprintf('http://127.0.0.1:%d%s', $this->port, $path);
    }
}

Now it’s pretty easy to test HTTP interactions:

class HttpLoaderTest extends AbstractHttpTest
{
    public function testUrlFailure()
    {
        $loader = new HttpLoader();
        $this->assertFalse($loader->load('this://does/not:work!'));
    }
 
    public function testSuccessfulRequestWithoutData()
    {
        $this->startServer(__DIR__ . '/../Fixtures/success_router.php');
 
        $loader = new HttpLoader();
        $response = $loader->load($this->createUrl('/foo/bar'));
 
        $this->assertEquals(200, $response['status']);
        $this->assertEquals('', $response['content']);
        $this->assertEquals('/foo/bar', $response['headers']['Foo-Bar']);
 
        $this->stopServer();
    }
 
    public function testSuccessfulRequestWithData()
    {
        $this->startServer(__DIR__ . '/../Fixtures/success_router.php');
 
        $loader = new HttpLoader();
        $response = $loader->load($this->createUrl('/foo/bar'), 'foo bar');
 
        $this->assertEquals('foo bar', $response['content']);
 
        $this->stopServer();
    }
 
    public function test404Error()
    {
        $this->startServer(__DIR__ . '/../Fixtures/error_router.php');
 
        $loader = new HttpLoader();
        $response = $loader->load($this->createUrl('/'));
 
        $this->assertEquals(404, $response['status']);
 
        $this->stopServer();
    }
}

And that’s it for today :)

Read More

Using a DataTransformer to save tags for an object in Symfony

Today I want to show you how tags can be edited and saved comfortably using a form and a DataTransformer. My Document looks like this:

namespace MyName\MyBundle\Document;
 
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use Symfony\Component\Validator\Constraints as Assert;
 
/**
 * @MongoDB\Document()
 */
class Post
{
    /**
     * @MongoDB\Collection
     */
    private $tags = array();
 
    public function getTags()
    {
        return $this->tags;
    }
 
    public function setTags(array $tags)
    {
        $this->tags = $tags;
    }
 
    // other fields like title and text and other setters/getters
}

Now I want that the user can edit a Post with a form. There I want the user to type a list of tags, separated by commas. This means I have to get the form input, convert it to an array and save this array when the Post is saved. When I want to display the form I have to take the array of tags and transform it to a string with comma-separated tags. In Symfony I don’t have to do this manually in my controller. I can use such a DataTransformer:

namespace MyName\MyBundle\Form\DataTransformer;
 
use Symfony\Component\Form\DataTransformerInterface;
 
class TagsTransformer implements DataTransformerInterface
{
    /**
      * Transforms the Document's value to a value for the form field
      */
    public function transform($tags)
    {
        if (!$tags) {
            $tags = array(); // default value
        }
 
        return implode(', ', $tags); // concatenate the tags to one string
    }
 
    /**
      * Transforms the value the users has typed to a value that suits the field in the Document
      */
    public function reverseTransform($tags)
    {
        if (!$tags) {
            $tags = ''; // default
        }
 
        return array_filter(array_map('trim', explode(',', $tags)));
        // 1. Split the string with commas
        // 2. Remove whitespaces around the tags
        // 3. Remove empty elements (like in "tag1,tag2, ,,tag3,tag4")
    }
}

Now you can create a new “tags” form type and use this transformer:

namespace MyName\MyBundle\Form\Type;
 
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use MyName\MyBundle\Form\DataTransformer\TagsTransformer;
 
class TagsType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder->appendClientTransformer(new TagsTransformer());
    }
 
    public function getParent(array $options)
    {
        return 'text';
    }
 
    public function getName()
    {
        return 'tags';
    }
}

This new type can be used in the form type of the document:

namespace MyName\MyBundle\Form\Type;
 
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Event\DataEvent;
 
use MyName\MyBundle\Form\Type\TagsType;
 
class PostDocumentType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder->add('title');
        $builder->add('date');
        $builder->add('text');
        $builder->add('tags', new TagsType()); // add tags field
    }
 
    public function getDefaultOptions(array $options)
    {
        return array(
            'data_class' => 'MyName\MyBundle\Document\Post',
        );
    }
 
    public function getName()
    {
        return 'post_document';
    }
}

And that’s it. Never ever waste time parsing a list of tags :)

Read More

MongoDB, Doctrine and Symfony 2.0.11

Today I wanted to update my Symfony applications to version 2.0.11 of the Symfony Standard Edition. In earlier versions you had to add the following three entries to your deps file in order to use MongoDB:

[doctrine-mongodb]
git=http://github.com/doctrine/mongodb.git
 
[doctrine-mongodb-odm]
git=http://github.com/doctrine/mongodb-odm.git
 
[DoctrineMongoDBBundle]
git=http://github.com/doctrine/DoctrineMongoDBBundle.git
target=/bundles/Doctrine/Bundle/MongoDBBundle
version=origin/2.0

DoctrineMongoDBBundle had (and still has) to be locked to version 2.0, otherwise it won’t play well with the other components.

Now, in Symfony 2.0.10 and 2.0.11 the doctrine-commons component has been updated to version 2.1.4, while the master branch of doctrine-mongodb-odm now needs version 2.2.0. Therefore you have to additionally update the version of this bundle. Because it is defined in deps.lock you have to change the line there:

doctrine-common 2.2.0

And that’s it. Now you can use MongoDB with Symfony as usual :)

I have one additional tip: If you get an error message that says something about “setSlaveOk” you have to update PHP’s MongoDB plugin.

Read More

How to write host-aware Twig templates in Symfony

There is an easy way in Symfony to inject a global variable into every Twig template in an application, which is described here.
However there are some cases where you don’t what to inject a simple static variable, but something dynamic like the hostname of the current request (or even the request object itself). If you want to do something like this it’s a bit more complicated. Basically you create a new Twig extension and register it with the application.

After I wrote the article I noticed that there is a much easier way to get the hostname in Twig templates. You can access the request object with {{ app.request }} and the hostname with {{ app.request.host }}. Nevertheless the tutorial shows how to inject other global variables :)

Step 1: Create the extension
The first thing you have to do is to write a Twig extension. In order to to this you have to create a new class which inherits Twig_Extension. The only method you have to provide by convention is “getName”. Let’s say a bundle’s source code it located at “src/MyName/MyBundle”. Then you could create the file “src/MyName/MyBundle/Twig/Extension/HostnameExtension.php”. It’s not neccessary to create the subfolders also, but it helps to structure your project:

// src/MyName/MyBundle/Twig/Extension/HostnameExtension.php
namespace MyName\MyBundle\Twig\Extension;
 
use \Twig_Extension;
 
class HostnameExtension extends Twig_Extension
{
    public function getName() 
    {
        return 'myname.hostnameExtension';
    }
}

(more…)

Read More

Change user roles during a session in Symfony

Today I encountered a tricky problem with Symfony. If you change properties like the name or the password of your session user the information will be updated in the session automatically. Unfortunately there is one difference: If you change your model in a way that your getRoles method returns a different array of roles these are not updated in the session by default.
Symfony will just use the old roles array until the next real authentication.

So here is the simply solution: Just unauthenticate the user and Symfony will try to authenticate it again with the given credentials. This way the new roles will be loaded into the session.

public function activateAccountAction() {
    $token = $this->get( 'security.context' )->getToken();
    $token->getUser()->setSomethingThatAffectsTheRoleArray( true );
    // flush document manager or sth like that
    $token->setAuthenticated( false );
}

Read More

How to customize form rendering in Symfony

As an addition to the previous blog post I want to show you how you can customize the rendering of your form elements. One possibility is to render the label, the field and the errors one by one:

<form action="{{ path('registration') }}" method="post" {{ form_enctype(form) }}>
    {{ form_errors(form) }}
    E-Mail: {{ form_widget( form.email ) }}
    <span class="custom_errors">{{ form_errors( form.email ) }}</span>
    ....  
    {{ form_rest( form ) }}
    <input type="submit" value="Register" />
</form>

Maybe you want to use the same HTML structure for all form fields in the current template. Then you can tell the form renderer to use a certain Twig block to display the form rows:

{% form_theme form _self %}
 
{% block field_row %}
    {{ form_label( form ) }}
    {{ form_widget( form ) }}
    <div class="custom-errors">{{ form_errors(form) }}</div>
    <hr />
{% endblock field_row %}
 
<form action="{{ path('registration') }}" method="post" {{ form_enctype(form) }}>
    {{ form_errors(form) }}
    E-Mail: {{ form_row( form.email ) }}
    ....  
    {{ form_rest( form ) }}
    <input type="submit" value="Register" />
</form>

Great! But maybe you want to load the field_row block from another template. This is easily done by setting the name of the template file instead of _self:

{% form_theme form 'MyProjectBundle::form_elements.html.twig' %}
...

If you want to have the same theme for all the form fields in your project you don’t have to add this line to every single template file. You can create a hierachy of template files containing form theming blocks by adding the paths to the twig.form.resources configuration variable:

twig:
    form:
        resources:
            - 'MyProjectBundle::form_elements.html.twig'

Some useful links with more detailed information are:
Symfony Forms – Form Theming
How to customize form rendering

And here you can find the default theming file of Symfony. There you have an overview of the blocks you can overwrite in your custom theme templates.

Read More

How to use the “repeated” field type in Symfony

Today I want to write about how to use the “repeated” field type in Symfony. Let’s say you want to create a controller method which handles a registration form. So in order to create this form you could do something like this:

$registrationForm = $this->createFormBuilder()
    ->add( 'email' )
    ->add( 'password', 'repeated', array( 'type' => 'password', 'invalid_message' => 'Passwords do not match' ) )
    ->getForm();

The first argument in line 3 is the name of the field. The second argument contains the field type “repeated”. This means that two field will be generated for the form and the values have to be the same. Then you can define a “type”, which stands for the field type of the two generated fields. You could also use “email” to enforce the user to enter his email address twice. The optional parameter “invalid_message” sets a custom message that will be displayed if the entered values do not match.

The basic version of the corresponding Twig template would look as follows:

<form action="{{ path('registration') }}" method="post" {{ form_enctype(form) }}>
    {{ form_widget(form) }}
    <input type="submit" value="Register" />
</form>

If you render the form you will notice that there is a problem: The captions of the two password fields are “First” and “Second”. One way to change them is to use a little hack I presented some time ago. However, in most real world cases you don’t use form_widget, but display the fields one by one. This way it is totally easy to set custom labels:

<form action="{{ path('registration') }}" method="post" {{ form_enctype(form) }}>
    {{ form_errors(form) }}
    {{ form_row( form.email, { 'label': 'E-Mail:' } ) }}
    {{ form_errors( form.password ) }}
    {{ form_row( form.password.first, { 'label': 'Your password:' } ) }}     
    {{ form_row( form.password.second, { 'label': 'Repeat Password:' } ) }}     
    {{ form_rest( form ) }}
    <input type="submit" value="Register" />
</form>

I hope this short example helped the many visitors looking for keywords like “repeated fields” :)

Read More

How to load users from MongoDB in Symfony

In a previous blog post I wrote about how to implement a custom user provider for Symfony. I bothered with this because I wanted to create a user provider which uses a MongoDB document.
Today I learned that this isn’t necessary at all, because there already is one! It is provided by the MongoDB bundle, but you have to write a bit of configuration to use it.
The user provider itself is Symfony\Bundle\DoctrineMongoDBBundle\Security\DocumentUserProvider. It has to be instantiated as a service in order to use it. Therefore it takes three arguments:

  • The document manager
  • The name of the document which represents the user (it must implement UserInterface)
  • The property name which represents the user’s name

You can simply create an entry in your service configuration file of your bundle to create the service:

<?xml version="1.0" ?>
 
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
 
    <services>
        <service id="blogsh.my_project.user_provider" class="Symfony\Bundle\DoctrineMongoDBBundle\Security\DocumentUserProvider">
            <argument type="service" id="doctrine.odm.mongodb.document_manager" />
            <argument>Blogsh\MyProject\Document\User</argument>
            <argument>name</argument>
        </service>
    </services>
 
</container>

Then you can use the service as a user provider in your security configuration:

security:
    providers:
      main:
        id: blogsh.my_project.user_provider

And that’s it! If you need further information about the User class itself you can read the user provider tutorial.

Read More

Create a custom password encoder for Symfony

In the last post I showed you how to create a custom user provider for the Symfony framework. Today I want to show you how to implement your own algorithm to secure a password.

If you haven’t heard about the Ceasar cipher you can read about it on wikipedia. This encryption algorithm isn’t very secure, but it is quite easy to implement and understand. Therefore I’ll use it in this tutorial. Also I’ll use the directories and the project structure of the previous post.

Let’s start by creating a PasswordEncoderInterface implementation:

# /src/Blogsh/TestBundle/Service/CeasarCipherEncoder.php

namespace Blogsh\TestBundle\Service;
 
use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface;
 
class CeasarCipherEncoder implements PasswordEncoderInterface {
 
    const from = 'abcdefghijklmnopqrstuvwxyz';
    const to = 'gkxqyvnabmswzefitoclpjrdhu';
 
    public function encodePassword( $raw, $salt ) {
        return strtr( $raw, static::from, static::to );
    }
 
    public function isPasswordValid( $encoded, $raw, $salt ) {
        return $encoded === $this->encodePassword( $raw, $salt );
    }
 
}

(more…)

Read More