Switch lang to RU

Download Symfony

Latest Symfony version can be downloaded here

Symfony documentation

Symfony documentation can be found here (original Symfony2 documentation here)

Symfony community

Join to the Symfony's great community here

Silex - just add water?!

2

 

In the "week of symfony #244" was mentioned my article about Silex microframework. This is a good news, but the article available only on russian language. Below you can read it on english.

Prerequisites:

  • A multilanguage site with 5 language versions;
  • The site need to be redesigned;
Task:
Implementation:

Silex is a PHP microframework for PHP 5.3. It is built on the shoulders of Symfony2 and Pimple and also inspired by sinatra.

First of all we need to download Silex phar archive from official site. Or install it directly from the official Git repository: http://github.com/fabpot/Silex. After downloading need to create in server's docroot directory "lib" and move silex.phar into it.

Now we're ready to create site controller index.php:

<?php
// index.php
/**
 *
 * @package
 * @author     Dmitry Bykadorov <dmitry.bykadorov@gmail.com>
 * @version    SVN: $Id:  $
 */
 
require_once 'lib/silex.phar';
 
// Init
$app = new Silex\Application();
 
// Debug
$app['debug'] = true;
 
// ... application code will be placed below
 
$app->run();  
Then we need to create .htaccess file (it will be redirect each request to the controller):

# .htaccess
<IfModule mod_rewrite.c>    
    Options -MultiViews
    RewriteEngine On
    #RewriteBase /path/to/app
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>  
We want to use Twig as template language and Translation component from Symfony2 for internationalization. Both Twig and Translation component we'll initialize in the $app->before() method. Twig will be first:

// index.php
 
/**
 * Before action
 */
$app->before(function () use ($app) {
    // Registering Twig
    $app->register(new Silex\Extension\TwigExtension(), array(
        'twig.path' => realpath(__DIR__.'/resources/views'), // templates will be placed in directory resources/views in docroot
        'twig.class_path' => realpath(__DIR__.'/lib/vendor/twig/lib'), // Twig lib will be blaced in lib/vendor/twig/lib
    ));
}
All Silex actions will be defined as closures, same as before() method.

Now Twig has been initialized, but also need to add water download and install Twig library (which doesn't included in Silex) in lib/vendor/Twig directory:

/lib
    /vendor
        /twig
            /lib
                /Twig
                    /Error
                    /Extension
                    /...  
Now we can create index action and its template:

// index.php
/**
 * Root
 */
$app->get('/', function () use ($app) {
    return $app->redirect("/en/about"); // path / - by default redirected to /en/about
});
$app->get('/{locale}', function () use ($app) {
    $locale = $app['request']->get('locale');
    return $app->redirect("/{$locale}/about"); // path /{locale} - by default redirected to /{locale}/about
});
$app->get('/{locale}/', function () use ($app) {
    $locale = $app['request']->get('locale');
    return $app->redirect("/{$locale}/about"); // path /{locale}/ - by default redirected to /{locale}/about
})->bind('homepage'); // set named route
Our site have "about" page as homepage - here's why we've created three index actions (if you know more elegant way - please email me). In code above we've introduced locale parameter. So it's time to initialize Translation component. Go back to the $app->before() method:

// index.php
$app->before(function () use ($app) {
    // ... Twig initialization
 
    // Define locale
    if ($locale = $app['request']->get('locale')) {
        $app['locale'] = $locale;
    } else {
        $app['locale'] = 'en';
    }
 
    // Register Translation component
    $app->register(new Silex\Extension\TranslationExtension(), array(
        'locale' => $locale, // Current locale
        'locale_fallback' => 'en', // Default locale
        'translation.class_path' => realpath(__DIR__.'/lib/vendor/symfony/src'), // Component classes path
    ));
 
    // Translation files (in YAML format)
    $app['translator.messages'] = array(
        'en' => realpath(__DIR__.'/resources/locales/en.yml'),
        'de' => realpath(__DIR__.'/resources/locales/de.yml'),
        'hu' => realpath(__DIR__.'/resources/locales/hu.yml'),
        'ru' => realpath(__DIR__.'/resources/locales/ru.yml'),
        'sk' => realpath(__DIR__.'/resources/locales/sk.yml'),
    );
    // YAML loader initialization
    $app['translator.loader'] = new Symfony\Component\Translation\Loader\YamlFileLoader();
 
    // Twig translation extension initialisation (allow to use tag {% trans %} and filter | trans in templates)
    $app['twig']->addExtension(new Symfony\Bridge\Twig\Extension\TranslationExtension($app['translator']));
}  
Ok, but here we also need to add more water download and install Translation component and some more components for support YAML e.t.c. Most simple way to acheive this - download standard Symfony2 library (at the end of this article I'll show important components - so we'll be able to remove unnecessary code). So, the directory structure would look like this:

/lib
    /vendor
        /symfony
            /src
                /Symfony
                    /Bridge
                        / ...
                    /Bundle
                        / ...
                    /Component
                        / ...  
Let's create about action:

// index.php
/**
 * About
 */
$app->get('/{locale}/about', function () use ($app) {
    return $app['twig']->render('about.twig', array(
        'locale' => $app['request']->get('locale'),
    ));
})->bind('about');  
About action will render /resources/views/about.twig template. But we lost our layout!

<!-- /resources/views/layout.twig -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <title>{% block pageTitle %}{% endblock %}</title>
</head>
<body>
    {% block content %}{% endblock %}
</body>
</html>  
Now we can creae /resources/views/about.twig template:

<!-- /resources/views/about.twig -->
{% extends "layout.twig" %}
 
{% block pageTitle %}
    {{ 'page.about.title' | trans }}
{% endblock %}
 
{% block content %}
    {{ 'page.about.title' | trans }}
{% endblock %}  
Note that here we have already used Twig and Translation. We have a first sentence for the file transfer. Let's create a translation file for default language:

# /resources/locales/en.yml
page.about.title: About Us  
The rest - it's a matter of time. Creating content for different languages ​​or take it from the database (this would require Doctrine2), fill in the translation files with tokens, write the necessary GET / POST methods (as well as any other - Silex support them) ...

Finally, as I promised, an example of the structure of Symfony-directory for our example:

/Symfony
    /Bridge
        /Twig
    /Bundle
        /TwigBundle
    /Component
        /Config
        /Translation
        /Yaml  
This is a minimal set of Symfony classes (except Twig and Swiftmailer (optional)) to create a small website without a database.

Conclusion:

Experience has shown that Silex can be used for small multilanguage sites. However, knowledge of Symfony2 will be very useful.

Silex benefits:
  • all power of Symfony2 (templates, work with the database, and other components)in your hands;
  • reusing applications;
  • more simple configuration than Symfony2.
Thank you for your attention.

Share: Vote:

2 comments for "Silex - just add water?!"

  1. Marc 2011/11/02 17/42/53 Reply

    Very interesting article, it has helped me a lot. But you've 2 errors (maybe it's the CODE rendering engine you're using here). To enable Yaml Loader for translation and twig translation extension, you need to separate the namespace using slash, so instead of: // YAML loader initialization $app['translator.loader'] = new SymfonyComponentTranslationLoaderYamlFileLoader(); // Twig translation extension initialisation (allow to use tag {% trans %} and filter | trans in templates) $app['twig']->addExtension(new SymfonyBridgeTwigExtensionTranslationExtension($app['translator'])); You've to type: // YAML loader initialization $app['translator.loader'] = new Symfony/Component/Translation/Loader/YamlFileLoader(); // Twig translation extension initialisation (allow to use tag {% trans %} and filter | trans in templates) $app['twig']->addExtension(new Symfony/Bridge/Twig/Extension/TranslationExtension($app['translator']));

  2. Dmitry Bykadorov 2011/11/03 08/42/20 Reply

    Thanks, Mark! I'll fix it now.

Leave a comment