Security and Voters in Symfony 3.4

So the other day I was talking to one of our interns on the topic why it’s important to think about security and permissions when writing a backend app, and so I thought, why not write a blog post talking about it.

If you’ve coded a little bit with Symfony, you probably already know that the security component is very useful to secure your app in many ways. There’s different concepts we need to understand before we can talk about voters.

Authentication

The first part to think of when coding a backend app is authentication.

Wether it’s through a login page or a cookie header within the request, the user will have to be authenticated to access the secured part of your application. This way you will prevent anonymous users from accessing it.

How to do this is up to you, but there’s several bundles that help you get started. The most used one is FOSUserBundle. Alternatively, you can code your own custom authentication system and User entities, implementing Symfony’s UserInterface, so you can handle all the roles, etc. More info on implementing a custom authentication system here.

One way or the other, you’ll have to define roles in your application, specifically in role_hierarchy and access_control keys in your security.yml. Let’s look into these.

So for instance, let’s imagine a case where we have an art application, where artists upload their art.

Our security.yml role hierarchy could look something like this:

#app/config/security.yml
security:
	#...
    role_hierarchy:
        ROLE_ARTIST:      ROLE_USER
        ROLE_ADMIN:       [ROLE_ARTIST, ROLE_USER]
        #...

Once you have your authentication firewall up and running, it’s all about the authorization.

Authorization

This is when an already authenticated user is allowed or not into a specific part of an app.

For example, our ACL could look something like this:

#app/config/security.yml
security:
	#...
    access_control:	
        - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/admin, role: ROLE_USER }

This means that all URIs under /admin will need some type of authentitication.

Let’s imagine we defined a CRUD page with all artists on it, with the following uri in our controller: /admin/artist

So, right now, a user that has ROLE_USER might be able to see a CRUD page with all the users in it! This is wrong! Only a user with ROLE_ADMIN should be able to see that page right? To achieve this we can call the AuthenticateCheker service from Symfony’s security component, like so:

use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

/**
 * @Route("/admin/artist")
 */
class ArtistController extends Controller
{
	/**
	 * @Route("/")
	 */
	public function indexAction(Request $request)
	{
		if (false === $this->get('security.authorization_checker')->isGranted('ROLE_ADMIN')) {
	         throw $this->createAccessDeniedException('Unable to access this page!');
	    }
	    // ...
	}
}

Or with Symfony’s base Controller’s wrapper function

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

/**
 * @Route("/admin/artist")
 */
class ArtistController extends Controller
{
	/**
	 * @Route("/")
	 */
	public function indexAction(Request $request)
	{
		$this->denyAccessUnlessGranted('ROLE_ADMIN', null, 'Unable to access this page!');
		// ...
	}
}

You can even write the annotation, and the controller will be even thinner!

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

/**
 * @Route("/admin/artist")
 */
class ArtistController extends Controller
{
	/**
	 * @Route("/")
	 * @Security("has_role('ROLE_ADMIN')")
	 */
	public function indexAction(Request $request)
	{
		// ...
	}
	// ...
}

Ok, so far so good. We now have a page which is only allowed for admins to access, great!

Let’s talk about an artist being able to edit it’s own profile page.

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

/**
 * @Route("/admin/artist")
 */
class ArtistController extends Controller
{
	// ...

	/**
	 * @Route("/edit/{id}")
	 * @Security("has_role('ROLE_ARTIST')")
	 */
	public function editAction(Request $request, Artist $artist)
	{
		// ...
	}
	// ...
}

So we’ve just updated the role and that should do right? Wrong!

What about users who have the same roles, but are not allowed to see each others’ information!!

So for instance, the artist with id 34 should be able to access the URI the /admin/artist/edit/34 but should not be able to access /admin/artist/edit/35, /admin/artist/edit/36,… etc.

Well, that’s where voters come in. This is such a key part of the application and it’s important you take it into account. Do not just secure your actions with roles, secure it with voters. The last thing you want is to have security holes in your application!

So in our previous example, artist with id 34 should only be able to access /admin/artist/edit/34 right? Let’s see how it can be done.

Security Voters

Voters are the services that decide which user can see or access what page. Conceptually, they are called voters because they vote, just like a Parliament or the Government, if a user can access certain information. They vote in favour (ACCESS_GRANTED), against (ACCESS_DENIED) or they abstain themselves (ACCESS_ABSTAIN) when they do not have enough information.

How to build a Voter

A Voter has to implement the VoterInterface. You can implement it yourself, or you can extend the abstract class Voter, which already has some logic into it.

This is what an Artist Voter would look like in our example.


namespace AppBundle\Security;

use AppBundle\Entity\Artist;
use AppBundle\Entity\User;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;

class ArtistVoter extends Voter
{
    // these strings are just invented: you can use anything
    const VIEW = 'view';
    const EDIT = 'edit';

    private $decisionManager;

    public function __construct(AccessDecisionManagerInterface $decisionManager)
    {
        $this->decisionManager = $decisionManager;
    }

    protected function supports($attribute, $subject)
    {
        // if the attribute isn't one we support, return false
        if (!in_array($attribute, array(self::VIEW, self::EDIT))) {
            return false;
        }

        // only vote on Artist objects inside this voter
        if (!$subject instanceof Artist) {
            return false;
        }

        return true;
    }

    protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
    {
        $user = $token->getUser();

        if (!$user instanceof User) {
            // the user must be logged in; if not, deny access
            return false;
        }

        // ROLE_SUPER_ADMIN can do anything! The power!
        if ($this->decisionManager->decide($token, array('ROLE_ADMIN'))) {
            return true;
        }

        // you know $subject is a Artist object, thanks to supports
        /** @var Artist $artist */
        $artist = $subject;

        switch ($attribute) {
            case self::VIEW:
                return $this->canView($artist, $user);
            case self::EDIT:
                return $this->canEdit($artist, $user);
        }

        throw new \LogicException('This code should not be reached!');
    }

    private function canView(Artist $artist, User $user)
    {
        // if they can edit, they can view
        if ($this->canEdit($artist, $user)) {
            return true;
        }

        // the Artist object could have, for example, a method isPrivate()
        // that checks a boolean $private property
        return $user === $artist->getUser();
    }

    private function canEdit(Artist $artist, User $user)
    {
        // this assumes that the data object has a getOwner() method
        // to get the entity of the user who owns this data object
        return $user === $artist->getUser();
    }
}

So the code is pretty self explanatory. There are two functions which we must implement when extending the Voter,

protected function supports($attribute, $subject)

and

protected function voteOnAttribute($attribute, $subject, TokenInterface $token)

.

The other two functions are private functions that are called in the above two. The private functions contain the logic. In our case, it’ll return true if an user is the owner of the artist entity, and false if anything else. Also, if the user has an admin role, it’ll also return true.

The supports function is telling that this Artist Voter will just vote about Artist entities, nothing else. And it’ll also vote on ‘edit’ and ‘view’ attributes, nothing else. If subject and attributes match, it’ll return the result of the vote, which will be a true or false on this case, as it’s what we need in the if section of the

public function vote(TokenInterface $token, $subject, array $attributes)

function of the abstract Voter.

Now let’s use this voter in our artist edit action:

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

/**
 * @Route("/admin/artist")
 */
class ArtistController extends Controller
{
	// ...

	/**
	 * @Route("/edit/{id}")
	 * @Security("has_role('ROLE_ARTIST')")
	 */
	public function editAction(Request $request, Artist $artist)
	{
		$this->denyAccessUnlessGranted('edit', $artist);
		// ...
	}
	// ...
}

That would now protect our URI from users who are trying to edit someone else’s page.

Let’s look a bit more into the the wrapper function

$this->denyAccessUnlessGranted('edit', $artist)

from Symfony’s Controller, which uses Symfony’s ControlTrait.

namespace Symfony\Bundle\FrameworkBundle\Controller;

trait ControllerTrait
{
	//...

	/**
     * Throws an exception unless the attributes are granted against the current authentication token and optionally
     * supplied subject.
     *
     * @param mixed  $attributes The attributes
     * @param mixed  $subject    The subject
     * @param string $message    The message passed to the exception
     *
     * @throws AccessDeniedException
     *
     * @final since version 3.4
     */
    protected function denyAccessUnlessGranted($attributes, $subject = null, $message = 'Access Denied.')
    {
        if (!$this->isGranted($attributes, $subject)) {
            $exception = $this->createAccessDeniedException($message);
            $exception->setAttributes($attributes);
            $exception->setSubject($subject);

            throw $exception;
        }
    }

    //...
}

So basically, the second parameter is the subject, AKA, the object we’re trying to edit.

So calling the above function

$this->denyAccessUnlessGranted('edit', $artist);

is the same as calling

$this->get('security.authorization_checker')->isGranted('edit', $artist)

like so:

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

/**
 * @Route("/admin/artist")
 */
class ArtistController extends Controller
{
	// ...

	/**
	 * @Route("/edit/{id}")
	 * @Security("has_role('ROLE_ARTIST')")
	 */
	public function editAction(Request $request, Artist $artist)
	{
		if (false === $this->get('security.authorization_checker')->isGranted('edit', $artist)) {
         	throw $this->createAccessDeniedException('Unable to access this page!');
    	}
		// ...
	}
	// ...
}

So as you can see, we’re calling the same function as at the beggining when we wanted to secure the indexAction with the function

$this->get('security.authorization_checker')->isGranted(...)

except this time, we’re seding a second parameter, the subject.

What this piece of code will do is trigger the hook of all voters that implement VoterInterface in your application and try to vote.

And if we look a bit deeper what the vote function does, you can find this code in the abstract class Voter, which we just extended to create our ArtistVoter.

namespace Symfony\Component\Security\Core\Authorization\Voter;

use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;

/**
 * Voter is an abstract default implementation of a voter.
 *
 * @author Roman Marintšenko 
 * @author Grégoire Pineau 
 */
abstract class Voter implements VoterInterface
{

    /**
     * {@inheritdoc}
     */
    public function vote(TokenInterface $token, $subject, array $attributes)
    {
        // abstain vote by default in case none of the attributes are supported
        $vote = self::ACCESS_ABSTAIN;

        foreach ($attributes as $attribute) {
            if (!$this->supports($attribute, $subject)) {
                continue;
            }

            // as soon as at least one attribute is supported, default is to deny access
            $vote = self::ACCESS_DENIED;

            if ($this->voteOnAttribute($attribute, $subject, $token)) {
                // grant access as soon as at least one attribute returns a positive response
                return self::ACCESS_GRANTED;
            }
        }

        return $vote;
    }

    //...
}

In our example, if it supports the attribute ‘edit’ and the subject, in this case, an Artist entity, it’ll try to grant or deny the access. If it doesn’t support this attribute OR this subject, it’ll abstain itself and move on to the next voter.

The great thing about this is you can implement different voters with one same subject but different logic, and in the end, all votes will be counted and the application will decide if that user is granted or not the access, much like a democratic parliament 🙂

Hope this info is useful to understand a bit more what goes under the hood in Symfony’s security component, and how to make sure your app is always secure.

Happy coding!! 🙂

Authentication here.
Authorization here.
Security component here.
Security configuration here.
Voters documentation here.

Symfony 3.4 PHPUnit testing database data

Hey guys, this post is a follow up from my last phpunit in Symfony2 post. This time I’ve had to install a test environment in a Symfony 3.4 project and I’ve had some weird problems, so I thought of writing this blog post once I solved them all, it may be helpful to someone out there 🙂

Step 1 – Installing a fresh Symfony 3.4 project.

In your symfony project, run the composer require

symfony new my_project 3.4

Now run the phpunit command to run tests.

cd my_project
# if you have the phpunit phar installed globally
phpunit tests/
# if you use the phar file directly
php phpunit.phar tests/

Right off the bat, it’ll give you an error…

PHPUnit 5.7.21 by Sebastian Bergmann and contributors.

E                                                                   1 / 1 (100%)

Time: 128 ms, Memory: 14.00MB

There was 1 error:

1) Tests\AppBundle\Controller\DefaultControllerTest::testIndex
Error: Call to undefined method Symfony\Component\Yaml\Parser::parseFile()

This problem is due to an incompatibility with code dependencies from PHPUnit and Symfony 3.2+ code, specifically with the Yaml component.

Don’t panic though, PHPUnit is working to solve this issue.

More info on the PHPUnit issue here.
More info on Symfony’s explanation here.

In the meantime, we can use the PHPUnit bridge to test our application.

cd my_project
composer require --dev symfony/phpunit-bridge

Once your composer json and lock have updated, it’s time to run the test!

./vendor/bin/simple-phpunit

It works!!

Step 2 – Installing doctrine’s fixtures bundle.

First run the composer require

composer require --dev doctrine/doctrine-fixtures-bundle

Once your composer json and lock have updated, it’s time to install it in our Kernel.

// app/AppKernel.php

// ...
if (in_array($this->getEnvironment(), ['dev', 'test'], true)) {
    // ...
    $bundles[] = new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle();
}

Now it’s installed, let’s create our first fixture. Let’s suposse we installed FOSUserBundle to manage our users, so for instance we could create a couple users like so:

// AppBundle/DataFixtures/ORM/LoadUserData.php

namespace AppBundle\DataFixtures\ORM;

use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use AppBundle\Entity\User;

class LoadUserData implements FixtureInterface, ContainerAwareInterface
{
    private $data = [
        'ROLE_USER' => [
            'username' => 'user',
            'email' => 'user@slowcode.io',
            'plainPassword' => 'user@slowcode.io'
        ],
        'ROLE_ADMIN' => [
            'username' => 'admin',
            'email' => 'admin@slowcode.io',
            'plainPassword' => 'admin@slowcode.io'
        ],
    ];

    private $container;

    public function setContainer(ContainerInterface $container = null)
    {
        $this->container = $container;
    }

    public function load(ObjectManager $manager)
    {
        $userManager = $this->container->get('fos_user.user_manager');

        foreach ($this->data as $role => $attrs) {
            $user = $userManager->createUser();
            foreach ($attrs as $attr => $val) {
                $function = 'set'. ucwords($attr);
                $user->$function($val);
                $user->setEnabled(true);
            }
            $user->setRoles(['ROLE_USER', $role]);
            $userManager->updateUser($user, true);
        }
    }
}

Now if we run the fixtures like so

php bin/console doctrine:fixtures:load --append

We’ll get another error:

In LoadDataFixturesDoctrineCommand.php line 95:
                                                
  [InvalidArgumentException]                    
  Could not find any fixture services to load. 

To fix this, we’ll need to add this to services.yml

# services.yml
services:
    # ...
    AppBundle\DataFixtures\:
        resource: '../../src/AppBundle/DataFixtures'
        tags: ['doctrine.fixture.orm']

Yes, you guessed it, the magic here relies on the tag. Doctrine will load all services that have that ‘doctrine.fixture.orm’ tag. On the other hand, it’ll also load all the classes that implement the ORMFixtureInterface (for instance, those classes extending the Fixture class). More info on all of this in the DoctrineFixtureBundle doc page.

Step 3 – Setting a separate database for testing.

Add these lines on your config_test.yml file.

# config_test.yml
# ...
# Doctrine Configuration
doctrine:
    dbal:
        driver:   "%test_database_driver%"
        host:     "%test_database_host%"
        port:     "%test_database_port%"
        dbname:   "%test_database_name%"
        user:     "%test_database_user%"
        password: "%test_database_password%"

This will point to the new test database.

Then add the data in parameters.yml (don’t forget parameters.yml.dist for future installs)

# parameters.yml
parameters:
    # ...
    test_database_driver: pdo_mysql
    test_database_host: localhost
    test_database_port: null
    test_database_name: test_db_name
    test_database_user: test_db_user
    test_database_password: test_db_pw

Step 4 – Creating a TestCase that we will extend when ddbb fixtures are needed.

This is useful for reusing code, instead of writing it on every file. It also makes all the fixture tests more consistent.

 //tests/AppBundle/DataFixtures/DataFixtureTestCase.php
namespace Tests\AppBundle\DataFixtures;

use Doctrine\ORM\EntityManager;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Input\StringInput;
use Symfony\Bundle\FrameworkBundle\Client;
use Symfony\Component\DependencyInjection\ContainerInterface;

class DataFixtureTestCase extends WebTestCase
{
    /** @var  Application $application */
    protected static $application;

    /** @var  Client $client */
    protected $client;
    
    /** @var  ContainerInterface $container */
    protected $container;

    /** @var  EntityManager $entityManager */
    protected $entityManager;

    /**
     * {@inheritDoc}
     */
    public function setUp()
    {
        self::runCommand('doctrine:database:drop --force');
        self::runCommand('doctrine:database:create');
        self::runCommand('doctrine:schema:create');
        self::runCommand('doctrine:fixtures:load --append --no-interaction');

        $this->client = static::createClient();
        $this->container = $this->client->getContainer();
        $this->entityManager = $this->container->get('doctrine.orm.entity_manager');

        parent::setUp();
    }

    protected static function runCommand($command)
    {
        $command = sprintf('%s --quiet', $command);

        return self::getApplication()->run(new StringInput($command));
    }

    protected static function getApplication()
    {
        if (null === self::$application) {
            $client = static::createClient();

            self::$application = new Application($client->getKernel());
            self::$application->setAutoExit(false);
        }

        return self::$application;
    }
    
    /**
     * {@inheritDoc}
     */
    protected function tearDown()
    {
        self::runCommand('doctrine:database:drop --force');

        parent::tearDown();

        $this->entityManager->close();
        $this->entityManager = null; // avoid memory leaks
    }
}

This will create the database and install the fixtures on every test that extends this TestCase. This is important as you want a consistent database with the same data every time!

Step 5 – Creating the unit, functional and integration tests

After creating your test fixtures, now you can test your services logic easily by extending the TestCase we just created, like so.

// tests/AppBundle/User/FooTest.php

class FooTest extends DataFixtureTestCase
{
    protected $fooService;

    /**
     * {@inheritDoc}
     */
    public function setUp()
    {
        parent::setUp();
        $this->fooService = $this->container->get('app.service.foo');
    }

    public function test_get_two_users()
    {
        $users = $this->entityManager->getRepository(User::class)->findAll();
        $this->assertEquals(2, count($users));
    }

  
}

Now you just need to run the phpunit command like so

./vendor/bin/simple-phpunit

I’ve created a bash wrapper script called ‘test’ that contains just this line of code so now I just need to run

bash test

Happy coding and testing! 🙂

Translatable models for translatable website in Django

This post is about using model translations (without translation files) and showing some ways to send that translations to the front end where they can be rendered.

This post is not about installing modeltranslations in Django, there’s a comprehensive guide on how to do that here.

Study case: Translatable texts that need to be editable in the django admin backend, without translation files.

Once we’ve got the modeltranslations module installed, we need to create the model we want to translate.

I’ve created the model String, but you can call it whatever you want.

#your_app/models/string.py
from django.db import models

class String(models.Model):
    key = models.CharField(max_length=80)
    value = models.CharField(max_length=255, blank=True, null=True)

    def __str__(self):
        return self.key

Now we should register our model in the translation.py, and so we can specify what field(s) will be the translatable one.

#your_app/translation.py
class StringTranslationOptions(TranslationOptions):
    fields = ('value',)


translator.register(String, StringTranslationOptions)

In a database level, this model table called your_app_string will contain the translations for every key in a column for each language: value_en, value_es, …

If you have i18n patterns in your url settings, Django will automatically know what locale to serve you through it’s own middleware system. For more info on this, there’s a comprehensive guide here.

Otherwise, you can set the locale manually through the request, up to you. More info on this here.

Once Django already knows what’s the current locale, we just need to get the strings from the database. The modeltranslations module will automatically give us the value translated to the current locale.

Translating the front end

We are able to transfer the strings to the frontend templates through many ways. For instance, we could load the strings on every view before rendering the template. However, this is bit of a code smell, as code is too coupled and it’s not very mantainable. We can do better like so:

1. Using a Context Processor

#your_app/context_processors/trans.py
from your_app.models import String


def trans(request):
    trans = {}
    for string in String.objects.all():
        trans[string.key] = string.value

    return {'trans': trans}

Your’ll need to register the context processor in settings.py

#settings.py
TEMPLATES = [
    {	
    	'...',
        'OPTIONS': {
            'context_processors': [
            	'...',
                'your_app.context_processors.trans',
            ],
        },
    },
]

What this will do is, after every render function in our views, it’ll include the array of all translations. That’s why you don’t need to load any extra file in the template.

Now in the front end, you can use it like so:

{{ trans.hello_world }}

{{ trans.hello_world_wrong_key }}

This is similar to loading the strings just before every render in the views, however we’ve removed the coupling by centralizing the code in one place.

The main problem though is that if there’s a key that’s not included, Django will just ignore that key, not giving us any feedback if a translation is missing. This is annoying if we’re developing, as we won’t catch missing translations for certain keys.

2. Using a filter (templatetag)

#your_app/templatetags/trans.py
@register.filter(name='trans')
def trans(field):

    translations = {}
    for string in String.objects.all():
        translations[string.key] = string.value

    try:
        trans = translations[field.__str__()]
    except KeyError:
        trans = '[*' + field + '*]'

    return trans

Now in the front end, you can use it like so. This time, different from context_processor, we won’t need to register it in the settings.py but we do need to load it in the template.

{% load trans %}

{{ 'hello_world' | trans }}

{{ 'hello_world_wrong_key' | trans }}

This one gives feedback if the key doesn’t exist, but as you can see, it loads all the strings every time it finds a key to be rendered. This is very inefficient!

3. Using a simple tag (templatetag)

Very similar to the filter, but there’s a suttle difference, this one can load the context.

#your_app/templatetags/trans.py
@register.simple_tag(name='trans', takes_context=True)
def trans(context, field):
    translations = context.request.session.get('translations')

    if not translations:
        translations = {}
        for string in String.objects.all():
            translations[string.key] = string.value
        context.request.session['translations'] = translations

    try:
        trans = translations[field.__str__()]
    except KeyError:
        trans = '[*' + field + '*]'

    return trans

Loading the context allows us to save data in memory, so it doesn’t have to load the translations from the database every single time there’s a string to be translated.

In the front end we still need to load the tag.

{% load trans %}

{% trans 'hello_world' %}

{% trans 'hello_world_wrong_key' %}

This one is not only clean and efficient, it also gives feedback if a translation key doesn’t exist in the database. Furthermore, since we now have the context (it can’t be loaded with a filter), the translations will be loaded from the ddbb just once (when it tries to translate the first key). When there’s a second key to be translated, it’ll get the array of translations from the context and just give the value translated, or the key if it can’t find it.

So there you have it, three different ways to present the translations in the front end with a custom model translation.

Other useful resources:

Django translations
Django model translations

How to add attributes to form widgets in Django templates

This blog post is about templates in Django, specifically filters or pipes, whatever you call them – in Symfony we used to call them Twig Filters – and how to create them.

Let’s put I have to add a class “form-control” from bootstrap, and another class “select2” from the select2 library into a form widget. Since the form widget is rendered in the backend, it’s not clear how to add attributes before it’s rendered. In this example I had to create a pipe to add attributes to the form widget.

In Symfony’s Twig, it’s pretty simple to add attributes, like so:

{{ form_widget(form.start, {'attr': {'class': 'form-control select2'}} ) }}

In Django’s template we’ll need a bit of a workaround and create the pipe.

Creating the filter file, add_attr.py

from django import template
register = template.Library()


@register.filter(name='add_attr')
def add_attr(field, css):
    attrs = {}
    definition = css.split(',')

    for d in definition:
        if ':' not in d:
            attrs['class'] = d
        else:
            key, val = d.split(':')
            attrs[key] = val

    return field.as_widget(attrs=attrs)

This file should live in a folder called templatetags in your Django app.

Using the pipe in the template

To use it in a Django template, firstly add this widget in the top of the template, similar to the load static widget.

{% load add_attr %}

And now you can use it on any form widget as a function, like so

{{ form.start|add_attr:"class:form-control select2" }}

And that’s it! Your widget will have the classes form-control and select2.

Hope this helps. Alternatively, you can use a django library called django-widget-tweaks that helps you to do this, find the info here.

Happy coding! 🙂

From Symfony to Django

Lately I’ve been playing with Django (in a real project, not tutorials) and all I have to say is… Oh My God!! I’m so impressed with Django’s clarity, speed of development and “cleanliness”, that I’m even planning for it to become my main ‘go-to’ framework! Don’t get me wrong, I’ve been working with Symfony for a few years and it’s still going to be the main framework I use for PHP projects, and probably the most comfortable I’ll feel working with for a while, but right now Django is like a new toy and I’m really excited to share this with you!

Furthermore, Django seems to perform far better in performance tests (less CPU resources, faster response…) than Symfony. Check here for more info on this.

This blog post is not a ‘Django getting started guide’, there’s plenty of those online already. Please visit Django’s oficial page for more info on this.

This blog post is for Symfony developers who wish to try Django out and are unaware of the Django project structure, file structure, etc. I’m going to go through the basics so you get a feel of what it’s like to code in Django and hopefully you feel comfortable enough to give it a go 🙂

Routing

Routing files are the ones which have mapped the routes for our application. Symfony and Django alike will try to match one of these routes to handle it.

Symfony annotations in controller

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

/**
 * Displays a form to edit an existing customer entity.
 *
 * @Route("/{id}/edit", name="app_customer_edit")
 */

Symfony YAML: routing.yml

app_customer_edit:
    path:     /{id}/edit
    defaults: { _controller: AppBundle:Customer:edit }

In Symfony you can include specific routing of a bundle like so:

app:
    resource:   "@AppBundle/Resources/config/routing.yml"
    prefix:     /

Django: urls.py

Django routing in a config file called urls.py

from app.views import customer

urlpatterns = [
    url(r'^(?P\d+)/edit$', customer.update_customer, name='customer_edit'),
]

You can also include specific routing in Django

urlpatterns = [
    url(r'^customer/', include('app.urls.customer')),
]

Controllers

Once matched a certain route, Controllers are the ones that receive the request and return a response, with whatever logic you may need in between, using services and so on.

Symfony: CustomerController.php

A Controller in Symfony, which has the action that will fire if the route matches

/**
 * Customer controller.
 *
 * @Route("customer")
 */
class CustomerController extends CoreController
{

    /**
     * Displays a form to edit an existing customer entity.
     *
     * @Route("/{id}/edit", name="app_customer_edit")
     */
    public function editAction(Request $request, Customer $customer)
    {
    
        //custom logic
    
        return $this->render('AppBundle:Customer:edit.html.twig', array(
                'param1' => $param1,
                //...
            ));
    }

}

Django: views.py

In Django, the Controller is called View, so the views.py will have the function we specified in the urls.py

def update_customer(request, pk):

    //custom logic

    return render(request, 'customer/edit.html', {
        'param1': param1,
    })

Template rendering

The templating engine is very very similar, so you won’t have any trouble adapting to the new one.

Symfony: edit.html.twig

Twig is the template engine in Symfony. The Resources/views folder in Symfony which contains all the twigs.

For instance, to create an anchor for a Symfony route in twig:

< a href="{{ path('app_customer_edit', { 'id': customer.id }) }}"> Edit the customer < /a>

Django: edit.html

Django uses it’s own templating engine, and the folder containing all the html files is called templates. Code looks very similar.

< a href="{% url "customer_edit" customer.id %}"> Edit the Customer < /a>

Static files

Symfony: public/

The Resources/public folder in Symfony which contains all the js/css files for later deployment.

To load some of those files in the template in Twig

< link rel="stylesheet" href="{{ asset('bundles/app/vendor/bootstrap/css/bootstrap.min.css') }}">
< script type="text/javascript" src="{{ asset('bundles/app/vendor/bootstrap/js/bootstrap.min.js') }}">

Django: static/

In Django, these files are gathered in a folder called static.

{% load static %}

< link rel="stylesheet" href="{% static "vendor/bootstrap/dist/css/bootstrap.min.css" %}">
< script src="{% static "vendor/bootstrap/dist/js/bootstrap.min.js" %}">

Entities

Entities are mapped models that translate into database tables. The idea is to abstract the database completely, so you can either use Mysql, Mongo, PostgreSql,… totally independent from the code.

Symfony: Customer.php

Using Doctrine, the Customer entity under the Entity folder in Symfony would look something like this:

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity()
 * @ORM\Table(name="app_customer")
 */
class Customer
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=50, nullable=true)
     */
    protected $name;

    /**
     * @var string
     *
     * @ORM\Column(name="surname", type="string", length=80, nullable=true)
     */
    protected $surname;

    /**
     * @var Address
     *
     * @ORM\OneToOne(targetEntity="Address", cascade={"persist"})
     * @ORM\JoinColumn(nullable=true)
     */
    protected $address;


    //more attributes...


	/**
     * @return string
     */
    public function __toString()
    {
        return trim((string) $this->getName(). ' '.  $this->getSurname());
    }
    
    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     *
     * @return Customer
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set surname
     *
     * @param string $surname
     *
     * @return Customer
     */
    public function setSurname($surname)
    {
        $this->surname = $surname;

        return $this;
    }

    /**
     * Get surname
     *
     * @return string
     */
    public function getSurname()
    {
        return $this->surname;
    }

    /**
     * Set address
     *
     * @param \AppBundle\Entity\Address $address
     *
     * @return Customer
     */
    public function setAddress(\AppBundle\Entity\Address $address = null)
    {
        $this->address = $address;

        return $this;
    }

    /**
     * Get address
     *
     * @return \AppBundle\Entity\Address
     */
    public function getAddress()
    {
        return $this->address;
    }

    //more getters and setters...

Django: models.py

In Django, much slimmer. No need of any getters and setters, as it has it’s own model API that handles that.

from django.db import models
from app.models.address import Address


class Customer(models.Model):
    name = models.CharField('Name', max_length=50)
    surnames = models.CharField('Surnames', max_length=80)
    address = models.OneToOneField(
        Address,
        on_delete=models.CASCADE
    )

    def __str__(self):
    	return self.name + ' ' + self.surnames

Forms

Symfony: FormType.php

In Symfony we’ll use a FormType, which usually extends from AbstractType. We also need to tell Symfony what class it’s mapping through the configureOptions method.

use Symfony\Component\Form\AbstractType;

class CustomerType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name', null, [
                'label' => 'Nom',
            ])
            ->add('items', CollectionType::class, [
                'entry_type' => CustomerItemType::class,
                'allow_add'    => true,
                'allow_delete' => true,
                'by_reference' => false
            ])
            ...
         ;
    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => Customer::class,
            'cascade_validation' => true,
        ));
    }

    /**
     * {@inheritdoc}
     */
    public function getBlockPrefix()
    {
        return 'appbundle_customer';
    }
}

To build the form from the controller we would use something like this

$form = $this->createForm(CustomerType::class, $customer);

This basically calls the form builder service and builds an CustomerType form with the $customer instance.

Django: forms.py

In Django it’s much simpler! We also need to tell Django what model class it’s mapping through the Meta assignment.

from django import forms

class CustomerForm(forms.ModelForm):

    class Meta:
        model = Customer
        exclude = ('',)

To build the form from the view we would use something like this

form_customer = CustomerForm(request.POST, instance=customer_inst)

Same as Symfony, this will create the form with the customer_inst instance.

ORM – Object Relational Manager

The ORM allows us to access objects from the database in a ‘object manner’, so we don’t need to worry how to access that DDBB, it’s totally independent.

Symfony: Doctrine

In Symfony we use Doctrine, so let’s find an Customer given a request id

public function editAction(Request $request)
{
	$em = $this->getDoctrine()->getManager();
	$customer = $em->getRepository('AppBundle:Customer')->find($request->get('id'));
	$customers = $em->getRepository('AppBundle:Customer')->findAll();
	$address = $customer->getAddress();

	// Find an customer depending on a address
	$customerInst = $em->getRepository('AppBundle:Customer')->findOneByAddress($addressInst);
}

Django: API

In Django it uses it’s own API.

def update_customer(request, pk):
    customer = Customer.objects.get(pk=your_object_id)
    customers = Customer.objects.all()
    address = customer.address

    # Find an customer depending on a address
    customer_inst = Customer.objects.get(address=address_inst)

Summary

I’m not saying Django is better than Symfony or the other way round. Each and every framework/technology has it’s place, and as developers, I believe we should be open minded and have as many tools as possible under the belt. So I strongly recommend every Symfony dev to try Django out if you haven’t done yet. I assure you that you’ll love everything about it, even the great admin it gives you out of the box 🙂

Docker for Symfony 4

This blog post is an introduction to devs who want to start using Docker with Symfony4. It will guide you through creating a Symfony 4 project running on Docker.

Before we start, you’ll need to install Docker in your machine. You can download it from the official website.

Once Docker is installed, I strongly recommend playing with the getting started guide. Here the guide for macs and here the guide for windows. However, if you’re lazy like me, just use this command to make sure it’s installed.

docker --version

Once all of that is out of the way, we can start with the Symfony 4 project and the Docker environment that will run it.

For the sake of the example, I’ve created a local environment running PHP5 to make things a bit trickier, since Symfony4 runs on PHP7.

Let’s try to create an empty SF4 skeleton on my local machine.

composer create-project symfony/skeleton symfony

Right off the bat I get the following error

[InvalidArgumentException]
Could not find package symfony/skeleton with stability stable in a version installable using your PHP version 5.6.29.

So as you can see, we’ve created an environment running PHP5 and we cannot create a SF4 project, which runs on PHP7. Docker should help us solve this problem 🙂

We have two cases I’m going to tap on.

Case 1: I’m creating a SF4 project from scratch and I want to set up a development environment with Docker.

Step1: Clone the docker-symfony4 repository which has the docker configuration files.

git clone https://github.com/joeymasip/docker-symfony4.git

Step2: Create the Symfony project skeleton.

First off, let’s start docker containters with the project we just downloaded.

#cd to the location where you cloned the project
cd ~/Development/docker-symfony4
#start the containers
docker-compose up -d 

This command starts the containers. The parameter -d makes them run in the background. If you omit the -d you’ll see the log.

Docker should start building (if it’s the first time for these images) and running with the containers in the background.

We will need to create the symfony project inside the php image bash, since it’s the only place we have PHP7. Remember we still have PHP5 in our machine, so first thing is to log into the bash for the php7 image.

docker-compose exec php-fpm bash

Once in there, we’re in a PHP7 image, so we should be able to create the skeleton for the symfony project.

#inside php-fpm bash
composer create-project symfony/skeleton symfony

Step3: Move the contents of the skeleton into the root of the application.

Unless you want to change the config of the working dir inside the docker-composer.yml, we need the symfony project to be in the root folder. Moreover, we can not clone the contents into the root folder directly like so (composer create-project symfony/skeleton .) because the installer deletes the contents of the folder you’re cloning into. Since it’s too risky, this option is not allowed. More info here.

Long story short, I’ve found this is the cleaner way to do it.

#inside php-fpm bash
mv /application/symfony/* /application
mv /application/symfony/.* /application

Now we can delete the empty folder we used for creating the skeleton

#inside php-fpm bash
rm -Rf /application/symfony

Step4: Require the components.

We can require whatever components we need.

#inside php-fpm bash
cd /application

composer require annotations
composer require --dev profiler
composer require twig
composer require orm
composer require form
composer require form validator
composer require maker-bundle

These are just a few, feel free to add the ones you want.

Step5: Creating some sample code in Symfony 4 project.

Now lets create a controller to test a sample route to make sure everything works.

#inside php-fpm bash
cd /application

bin/console make:controller Pizza

Now, open a new chrome tab and type the following URL. The port is the one we set up in the docker-compose.yml – If you check the dictionary of the ngix config, you can see that port 8000 maps the 80, which is the usual webserver port.

http://localhost:8000/pizza

We should now see our new controller action rendering a response.

Step6: Sync de database.

Finally, to sync the database, you need to update the .env file with the variables we set on the mysql image.

.env file that has been generated when requiring the orm package in Symfony4.

DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/db_name

So if you check the docker-compose.yml file, you’ll see the credentials under the mysql configuration. So change the file to

DATABASE_URL=mysql://dbuser:dbpw@mysql:3306/docker_symfony4

Finally, let’s restart the containers

docker-compose down
docker-compose up -d
docker-compose exec php-fpm bash

Now inside the bash, you should be able to

#inside php-fpm bash
bin/console doc:sch:crea

You can connect an external database client such as Sequel Pro or MysqlWorkbench.

For the credentials remember to put again the ones we set in the mysql image.

Host: 0.0.0.0
Username: dbuser
Password: dbpw
Port: 8002

Also as a reminder, every time you composer down or kill the mysqld image, your schema will disapear! This not only means you’ll have to recreate again the following time, it also means the data will be lost. So make sure to dump the data if you need it later, or create some demo data/fixtures so you don’t have to add data manually.

Case 2: I already have a SF4 project

Maybe you cloned from elsewhere, or maybe you created it in the past with PHP7 in your local machine.

Step1: Clone the docker-symfony4 repository which has the docker configuration files.

git clone https://github.com/joeymasip/docker-symfony4.git

Step2: Move the files from the docker-symfony4 project folder you just cloned into your Symfony project root.

Move the docker-compose.yml and the folder named phpdocker containing nginx and php-fpm config for it to the root of your Symfony4 project.

Step3: Start the docker images inside your Symfony4 project folder.

cd into your Symfony project folder and type the following command

docker-compose up -d

This command starts the containers. The parameter -d makes them run in the background. If you omit the -d you’ll see the log.

Docker should start building (if it’s the first time for these images) and running with the containers in the background.

Now, open a new chrome tab and type the following URL. The port is the one we set up in the docker-compose.yml – If you check the dictionary of the ngix config, you can see that port 8000 maps the 80, which is the usual webserver port.

http://localhost:8000
http://localhost:8000/whatever-slug-you-want-from-your-project

You should see it working.

You’re already set up to develop, so happy coding with docker!

Disclaimer: The project container I created has been generated in phpdocker.io

The new era of micro frameworks, welcome Symfony 4

Whoop Whoop! Symfony 3.4 and Symfony 4 were released a couple days ago with lots of hype around it!

But what is really different this time from other Symfony versions? Let’s have a look…

Decoupling components

First off, conceptually, Symfony framework is moving towards a more decoupled structure. You probably noticed that instead of creating a new project through the symfony installer, you now use the following command.

composer create-project symfony/skeleton your-project-name

 
The reason behind this is that in earlier versions, when creating a symfony project, you were installing lots of dependencies and components that you may or may not be using in your application.

The idea now is creating a skeleton type project, and then installing all the components we need for that project seperately. This allows the programer complete freedom to be using whatever component he or she needs.

This in turn means that each Symfony application you code might use different components, even if they were created by Symfony, and therefore you do not need to install all of them every time, which makes each project more light weight!

For example, an API project might not use Twig, so there’s no need to install it in the vendor directory right?

Or I might just install the command component because I need to write some php scripts and I need a quick wrapper to organise my code.

Neither of the projects above would need twig, or form, or entities, or orm… you get the point.

I still remember the days when you had one big bloated Symfony framework installed, and many apps inside it. Inside each app, there were bundles.

After that, it evolved into one app per symfony installation, and each app had it’s different bundles.

It’s now time for the bundle less symfony. Best practices now say that you should have one skeleton per project, and following the decoupling of components, each project will have just the component it needs. This is just great, because every project will now have the underlying code that is really necessary, and not a bloated version of all the Symfony components together.

Having said this, there’s a few components I use 99% of the time when creating websites, so I created this small wrapper script so it’s easy for me to get them all, feel free to grab it and add/remove at your taste :). I call it ‘symfony-create-project.sh’

#!/bin/bash
# This script is a wrapper for creating a skeleton and installing the basic components I use most of the time
# To use it: bash symfony-create-project name-of-your-project

if [ "$1" != "" ]; then
	composer create-project symfony/skeleton "$1"
	cd "$1"
	composer require annotations
	composer require --dev profiler
	composer require twig
	composer require orm
	composer require form
	composer require form validator
else
	echo "parameter expected: name-of-your-project"
fi

Directory Structure

First thing you notice is the disappearance of the web folder. You now have the public folder instead. Inside it we can also see that app.php and app_dev.php have disappeared. Instead, we now have a more default index.php. The environment will be controlled by a .env file in the root directory of the project.

Second of all, the whole Resources folder inside src/ has disapeard as well, and all of it’s contents are in different places. The config files (routing.yml, services.yml…) are in the config/ folder in the root directory. This makes sense now since we have bundle-less applications. All of the twig files have also moved to a general templates/ folder in the root directory.

Now the src/ folder is just for php code, which makes much more sense if you work on a team with frontend and backend dev’s, each of them can now focus on their own folder.

Autoconfiguring and Autowiring

This is my absolute favourite.

Let me just copy this with the comments, as it explains everything really well.

services:
    # default configuration for services in *this* file
    _defaults:
        autowire: true      # Automatically injects dependencies in your services.
        autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
        public: false       # Allows optimizing the container by removing unused services; this also means
                            # fetching services directly from the container via $container->get() won't work.
                            # The best practice is to be explicit about your dependencies anyway.

Let’s dive into the code.

So I created a new service class,

<?php

namespace App\Utils;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Routing\Annotation\Route;

class NumberGenerator
{
    public function __construct()
    {
    }

    public function getRandomNumber()
    {
        return  mt_rand(0, 100);
    }
}

Injected into the action,

<?php

namespace App\Controller;

use App\Utils\NumberGenerator;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Routing\Annotation\Route;

class DefaultController extends Controller
{
    /**
     * @Route("/default/home")
     */
    public function home(NumberGenerator $numberGenerator)
    {
        return $this->render('default/home.html.twig', array(
            'number' => $numberGenerator->getRandomNumber(),
        ));
    }
}

and BANG, it worked like expected.

Let’s recapitulate here… before, we had to create the service, add it in the dependency injection config file, and then get it from the container.

What we just did in Symfony4 is create the service and inject it in the action we needed it. No configuration, no getting… just injection. This REALLY speeds up the process, enough configuration and more coding!!

However, if you don’t want to inject your service in the action, you can still use the container with the get function as we did in the past, although best practices advise not to.

Firstly,


composer require dependency-injection

Secondly, we need to set the service to public.

services:

    App\Utils\NumberGenerator:
        public: true

You can now get the service from the container

...
return $this->render('default/home.html.twig', array(
            'number' => $this->get(NumberGenerator::class)->getRandomNumber(),
        ));
...

There’s another component/bundle, which although is not super necessary, makes your life much much easier: Yup, you guessed it, it’s the Maker Bundle

composer require maker-bundle

This components creates the skeleton files for you (controllers, entities, forms,… etc), for example

bin/console make:controller CarController

More info on the maker bundle here.
More info on all the different component recipes here.

Conclusion

I just love how Symfony keeps giving more and more control to the developer.

Lots uf us (me included) know that changing and evolving things that we’re used to doing is sometimes painful… but after playing with it a little bit, I see this upgrade as a great step forward for better code, better standards and better readability.

So thank you to the Symfony team and everyone who contributed for making this happen!

Happy coding!!

Namespaces and organizing business logic services in Symfony

I want to talk about namespacing services in Symfony, specifically Symfony3.

These are exciting times, Symfony 4 is just round the corner – coming out on November 30th – so this blog post might be irrelevant soon! Nevertheless, concepts are still the same so let´s get into it!

Lately, talking with my team in SlowCode, we defined a common way of defining services.

First rule – using a folder for logic services.

Any service which provides logic to the app would be inside a App\Service folder. This way everything is tidy, and all developers in the team know where to find them.

Second rule – using a folder for the domain name

The next layer is the domain name. This is again, to provide order. You might not think so, but when you end up with 8 domain names, and 2-3 services in each one, then things can get uggly if it’s not tidy 🙂

So for instance, let’s have a service that is related to Stock called StockAvailability, the service would end up with the namespace the folder AppBundle\Service\Stock\StockAvailability

Third rule – using . for folder separation and _ for word separation

The id of the service has to be separated by . when you enter into a new folder, and separated by _ when it’s more than one word.

So in the previous example, we would define the whole thing like so:

services:

    app.service.stock.stock_availability:
        class: AppBundle\Service\Stock\StockAvailability
        arguments:
            - '@doctrine.orm.entity_manager'
            ...

Lately in Symfony 3.3, a new way of defining services was brought up.

It´s now a good practice to define the id of the service with the full qualified name. So, instead of defining it like we did before, we would define it like so:

services:

    AppBundle\Service\Stock\StockAvailability:
    	public: true
        arguments:
            - '@doctrine.orm.entity_manager'
            ...

Declared like this, you can still get the service from the service container (with the new id of course, the full class name)

use AppBundle\Service\Stock\StockAvailability

public function fooAction(Request $request)
{
    // before Symfony 3.3, you would get it like so
    // $stockService = $this->get('app.service.stock.stock_availability');

    // in Symfony 3.3, you can get it like so
    // This is only available if you defined your service as public
    $stockService = $this->get(StockAvailability::class);
}

As Symfony’s official page point out, it’s a good practice to define your services as private, not public, and then inject any service you may need in the action inside the controller, instead of getting it from the service container (similar to the dependency injection inside services), for instance

use AppBundle\Service\Stock\StockAvailability

public function fooAction(Request $request, StockAvailability $stockService) { 
    // now we have it injected into our variable $stockService 
    // so we don't need to get it from the container 
} 

So first off, I think the id with the full class name instead of an invented nomenclature is a good thing. At least there will be no more confusion amongst different devs from the team.

About private/public services. I understand where Symfony is going, and I think restricting by ‘injecting’ instead of ‘getting’ makes code more robust, and probably more readable in the end. However, I still think there’s an upside on how things were prior to 3.3 version. Getting services from the container is VERY useful, and provices flexibility and speed.

I think that since you can still define public services, that’s what I’ll keep doing… what will you do?

More info here:
Symfony service container
Symfony 3.3 best practices
Symfony class for service id

Asking the right questions before building an MVP

This last week we’ve had two potential new clients ask us for an MVP RFQ (Request for quotation).

MVP means Minimal Viable Product, which in the software world means a very simple app that shows your future potential app in a simplified way.

An MVP is normally used to asses future app behaviour, get feedback from users and work from there, and also as a showcase for future investors – investors very rarely invest in ideas, they prefer to see something functional, with customer response and feedback if possible.

It is important that the MVP shows at least a very important feature of your future app. For example, for an ecommerce MPV, logging in a user is not as important as being able to buy a product.

So back to the story, these two clients contacted us and told us what they wanted in a very different way. It became very clear to me that client A knew exactly what he wanted, whilst client B did not. Client A gave direct answers, client B did not.

If a client doesn’t really know what he wants, asking for information becomes a hurdle, ideas seem to jump all around while nothing ever gets done. If you relate to this, you know how frustrating it is… specially because no one is paying for your time at this stage!!

So what’s really important at that moment is to ask the right questions. I cannot stress enough how important this is, because it sets the pace for the whole project.

For example,

Summarize your app in one sentence.
There is a reason why this is number one. This is the most important question – of course they can use more than one sentence, but asking them this puts them in a place where they have to really think of the most important element of the app, not just random features they’re going to add. This is key to understanding properly what your client wants.

What is the reason this app exists?
Spot the USP ‘Unique Selling Point’. There might be none, and this is also fine.

What is the budget for the app and for the MVP?
This will provide you with information of how big this app is going to be, at least at the beginning. The budget might not be a number, it might be a range. This is fine also, because then you’re able to scope the size of the whole project.

How will you make money from the app?
Sometimes clients think that we, as developers, don’t need this question answered, specially at an MVP level. I think it’s useful to know where the focus and priorities are going to be, so you can start thinking big and preparing for the future.

These are some of my non technical preferred questions. Believe me, they do the job right! Once, and only once, you get answers for these, you can start asking the technical ones – maybe that’s for a future post 🙂