My favorite stack

As I posted in an earlier post Javascript is conquering the world and in this post I want to share what is my favorite stack for building web applications.

For the latest apps I’m working I really like the following stack:

Symfony for the backend, basically the administrator interface.
AngularJS for the frontend and UI.
A RESTful API to be consumed by the frontend.

As I’m working with Symfony for a long time I decided to build my backend and administrator based on this PHP framework. For that I use a bundle I’ve written nammed HasheadoAdminBundle, but also I’m playing and experimenting with this EasyAdminBundle written by Javier Eguiluz.

For the frontend I’m using AngularJS, a really cool framework to extend HTML and build rich web applications. There is really good documentation to learn Angular in its own website and it also has a great community.

To build the RESTful API I’m using great Symfony bundles like FOSRestBundle and the JMSSerializerBundle. Here there is a really cool post to see how to build a cool API.

Well, I hope this post help you.

Hasheado Admin Bundle

This is the bundle I use for admin generator in Symfony application. Basically, it’s an extension of SonataAdminBundle, but with different UI and FOSUserBundle already integrated for user and authentication management.

You can find it in:
Packagist
Github

You can follow this documentation to install it and use it:

Step 1: Download the Bundle

NOTE: This bundle depends in the SonataAdminBundle, FOSUserBundle and in the SonataDoctrineORMAdminBundle.

In an already working Symfony installation edit your composer.json file and add this line:

1
2
3
require: {
    "hasheado/admin-bundle"
: "dev-master"
}

and then, open a command console, enter your project directory and execute the following command to download the latest stable version of this bundle:

1
user@unix:~$ composer update

This command requires you to have Composer installed globally, as explained in the installation chapter of the Composer documentation.

Step 2: Enable the bundle

To enable the bundle we need to add the following line in the app/AppKernel.php file of your project:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
// app/AppKernel.php

// ...
class AppKernel extends Kernel
{
    public function registerBundles()
    {
        $bundles = array(
            // ...

            // Add dependencies
            new Sonata\CoreBundle\SonataCoreBundle(),
            new Sonata\BlockBundle\SonataBlockBundle(),
            new Knp\Bundle\MenuBundle\KnpMenuBundle(),
            new Sonata\DoctrineORMAdminBundle\SonataDoctrineORMAdminBundle(),
            new FOS\UserBundle\FOSUserBundle(),
            new Sonata\UserBundle\SonataUserBundle('FOSUserBundle'),
            new Sonata\EasyExtendsBundle\SonataEasyExtendsBundle(),

            // Then add SonataAdminBundle
            new Sonata\AdminBundle\SonataAdminBundle(),
            // And HasheadoAdminBundle
            new Hasheado\AdminBundle\HasheadoAdminBundle(),

            // ...
        );
    }

    // ...
}
?>

Step 3: Configuration

If you followed the installation instructions, HasheadoAdminBundle should be installed but inaccessible. You first need to configure it for your models before you can start using it.

Import the HasheadoAdminBundle’s config files:

1
2
3
4
5
6
7
8
9
10
11
12
13
# app/config/config.yml
imports
:
    - { resource
: @HasheadoAdminBundle/Resources/config/config.yml }

sonata_user
:
    class
:
        user
: pathToYourBundle\Entity\User
        group
: pathToYourBundle\Entity\Group

    fos_user
:
        user_class
: pathToYourBundle\Entity\User
    group
:
        group_class
: pathToYourBundle\Entity\Group

Of course, replace the path to your User and/or Group entities, and do not forget to make your classes extend the Sonata\UserBundle\Entity\BaseUser and the Sonata\UserBundle\Entity\BaseGroup classes.

Then you need to add the below security configuration:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# app/config/security.yml
security
:
    role_hierarchy
:
        ROLE_ADMIN
: [ROLE_USER, ROLE_SONATA_ADMIN]
        ROLE_SUPER_ADMIN
: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
        SONATA
:
           - ROLE_SONATA_PAGE_ADMIN_PAGE_EDIT # if you are using acl then this line must be commented

    providers
:
        fos_userbundle
:
           id
: fos_user.user_manager

    encoders
:
        FOS\UserBundle\Model\UserInterface
: sha512

    firewalls
:
       # Disabling the security for the web debug toolbar, the profiler and Assetic.
        dev
:
            pattern
: ^/(_(profiler|wdt)|css|images|js)/
            security
: false

    # ->; custom firewall for the admin area of the URL
    admin
:
        pattern
: /admin(.*)
        context
: user
        form_login
:
            provider
: fos_userbundle
            login_path
: /admin/login
            use_forward
: false
            check_path
: /admin/login_check
            failure_path
: null
        logout
:
            path
: /admin/logout
            target
: /admin
            anonymous
: true

    # -> end custom configuration

    acl
:
        connection
: default

    access_control
:
       # Admin login page needs to be access without credential
        - { path
: ^/admin/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path
: ^/admin/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path
: ^/admin/login_check$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        # Secured part of the site
        # This config requires being logged for the whole site and having the admin role for the admin part.
        # Change these rules to adapt them to your needs
        - { path
: ^/admin/, role: [ROLE_ADMIN, ROLE_SONATA_ADMIN] }
        - { path
: ^/.*, role: IS_AUTHENTICATED_ANONYMOUSLY }

At this point, the bundle is functional, but not quite ready yet.

You need to update the schema:

1
user@unix:~$ php app/console doctrine:schema:update --force

and create a new root user:

1
user@unix:~$ php app/console fos:user:create --super-admin

To be able to access HasheadoAdminBundle’s pages, you need to add its routes to your application’s routing file:

1
2
3
# app/config/routing.yml
admin
:
    resource
: '@HasheadoAdminBundle/Resources/config/routing.yml'

Finally, publish the assets:

1
user@unix:~$ php app/console assets:install

At this point you can already access the (empty) admin dashboard by visiting the url: http://yoursite.local/admin/dashboard. And, start adding your admins following SonataAdminBundle documentation.

Symfony best practices

A couple months ago the Symfony creator Fabien Potencier, alongside Ryan Weaver and Javier Eguiluz have created a handbook called “Symfony Best Practices“.

The reason of this handbook was due to the community has created an unofficial set of recommendations for developing Symfony applications. Unfortunately, a lot of these recommendations are unneeded for web applications.

Here, a summary of these best practices:

Projects creation

Use the Symfony installer.

You can read about it in an earlier post.

About bundles:

Create only one bundle called AppBundle for your application logic

Configuration

Define the infrastructure-related configuration options in the app/config/parameters.yml file.

Define all your application’s parameters in the app/config/parameters.yml.dist file.

Define the application behavior related configuration options in the app/config/config.yml file.

Organizing our Business Logic

Services: Name and Format

The name of your application’s services should be as short as possible, but unique enough that you can search your project for the service if you ever need to.

Use the YAML format to define your own services.

Don’t define parameters for the classes of your services.

Using a Persistence Layer:

Use annotations to define the mapping information of the Doctrine entities.

Controllers

Make your controller extend the FrameworkBundle base Controller and use annotations to configure routing, caching and security whenever possible.

Routing configuration:

Don’t use the @Template() annotation to configure the template used by the controller.

Use the ParamConverter trick to automatically query for Doctrine entities when it’s simple and convenient.

Templates

Use Twig templating format for your templates.

Store all your application’s templates in app/Resources/views/ directory.

Twig extensions:

Define your Twig extensions in the AppBundle/Twig/ directory and configure them using the app/config/services.yml file.

Forms

Define your forms as PHP classes.

Add buttons in the templates, not in the form classes or the controllers.

Internationalization

Use the XLIFF format for your translation files.

Store the translation files in the app/Resources/translations/ directory.

Always use keys for translations instead of content strings.

Security

Unless you have two legitimately different authentication systems and users (e.g. form login for the main site and a token system for your API only), we recommend having only one firewall entry with the anonymous key enabled.

Use the bcrypt encoder for encoding your users’ passwords.

Web Assets

Store your assets in the web/ directory.

Use Assetic to compile, combine and minimize web assets, unless you’re comfortable with frontend tools like GruntJS.

Tests

Define a functional test that at least checks if your application pages are successfully loading.

Hardcode the URLs used in the functional tests instead of using the URL generator.

Well, a great handbook to follow up, but of course, this are “best practices” and they are not a must.

The Symfony Installer

Nice news! Symfony team has launched their own installer. The purpose of this installer is to start new projects based on the Symfony full-stack framework.

We can find how to install it and use it here.

As you can see it’s really easy to install and use. For instance, to create a new project (once installed) we can run:

1
user@unix:~$ symfony new my_project

Symfony keeps evolving :D.

Symfony2 final version is not there yet

As Fabian Potencier has posted in the Symfony’s blog, Symfony2 is not ready yet. The core team of Symfony has decided to delay the release of the Symfony2 final version.

The core architecture is now stable, except for a few changes in the naming conventions that will be done in the coming days.

Upgrading from one preview release to the next one is now easier, thanks to the new UPDATE document.

Also, the first beta is not out there because the core team is waiting for the last big modification that will possibly be merged: the form framework refactoring. Entering beta means that all the main features of the framework will be available.

So, looking forward for the beta release at least.