Silex mini framework pourquoi mini ?

Image non disponible

Silex est un framework PHP issu d'un autre framework PHP, Symfony2.
Il est généralement considéré comme étant un mini framework PHP. Je vais tenter de vous montrer qu'il est largement suffisant et puissant pour bon nombre de projets, même si le projet est volumineux.

14 commentaires Donner une note à l'article (5)

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Avant-propos

Il n'est pas possible à mon sens de parler de Silex sans faire allusion à Symfony2.
Alors de mon point de vue, je n'aime pas (encore) Symfony2.
Une des raisons est que je trouve que la prise en main de Symfony2 (SF2) est malaisée de prime abord.
Et c'est là qu'intervient Silex, ce (mini) framework, va être pour nous une porte d'entrée pour appréhender SF2.

I-A. Présentation

Silex est un framework PHP pour 5,3 PHP, inspiré du framework développé par Sensio Labs Symfony2.
Celui-ci a été créé par Fabien Potencier, père du framework Symfony, et Igor Wiedler, ingénieur logiciel. Il est publié sous licence MIT.
Silex est composé de Silex-Core, Twig qui est le template et certains composants de Symfony.
Silex utilise » Composer » :Composer est un outil moderne qui permet de gérer les dépendances de ses projets de manière simple et puissante.
Comme Silex est compilant 'psr-0', cela nous permet d'intégrer des bibliothèques externes très facilement.

I-B. Notre façon de travailler.

Il existe plusieurs façons de traiter et travailler avec Silex. Notamment Grégoire Pineau qui propose sa façon de faire, ou encore Mparaiso qui nous propose le fameux blog, c'est sur ce dernier que je me suis largement inspiré pour cet article.
Dans le projet que je dois mettre en place, il faut que cela soit maintenable, clair et précis.
Je mettrai donc en place une structure MVC (Model-View-Controller), et je vais distinguer deux parties. La première sera la mise en place de la structure et architecture de façon à disposer d'un outil prêt à l'emploi.
Cet outil se présentera en une arborescence définie, la mise en place de Silex, Twig et le bootstrap Twitter.

II.

II-A. Arborescence

Notre structure du nouveau projet SilexSkeleton va ressembler à ceci :

Image non disponible

II-B. Composer

À partir d'ici nous allons utiliser Composer pour gérer les dépendances de notre application, nous devons donc rapatrier cet outil.
Il existe plusieurs façons de faire et il existe plusieurs façons de l'utiliser, je vous laisse le soin de choisir selon votre préférence.
Une fois "Composer" installé, nous allons à la racine créer notre fichier de configuration JSON, qui va nous permettre de gérer nos dépendances.
Éditons un fichier nommer composer.json et plaçons-le à la racine de notre projet.

 
Sélectionnez
{
    "minimum-stability":"dev",
    "require":{
        "silex/silex":"1.0.*"
    }

}

Dans ce fichier nous demandons d'installer Silex version 1.0.*, l'astérisque représentant les sous-branches, mais avec un minimum de stabilité.
Lançons l'installation :

 
Sélectionnez
php composer.phar install

Ce qui chez moi donne ceci :

 
Sélectionnez

 This dev build of composer is outdated, please run "composer.phar self-update" to get the latest version.
Installing dependencies
  - Installing pimple/pimple (dev-master)
    Cloning b9f27b8dc18c08f00627dec02359b46a24791dc3

  - Installing symfony/routing (2.1.x-dev)
    Cloning v2.1.2

  - Installing symfony/http-foundation (2.1.x-dev)
    Cloning 17af0b966d268aa62e3487e3c48f0742e919edd1

  - Installing symfony/event-dispatcher (2.1.x-dev)
    Cloning v2.1.2

  - Installing symfony/http-kernel (2.1.x-dev)
    Cloning 9d00c6069a5e194826091d72baa5402f623ebf31

  - Installing silex/silex (dev-master)
    Cloning fc82b4255ef081dd7d464c5320ca93a902f9190f

symfony/routing suggests installing doctrine/common (=2.2,2.4-dev)
symfony/routing suggests installing symfony/config (2.1.*)
symfony/routing suggests installing symfony/yaml (2.1.*)
symfony/event-dispatcher suggests installing symfony/dependency-injection (2.1.*)
symfony/http-kernel suggests installing symfony/browser-kit (2.1.*)
symfony/http-kernel suggests installing symfony/class-loader (2.1.*)
symfony/http-kernel suggests installing symfony/config (2.1.*)
symfony/http-kernel suggests installing symfony/console (2.1.*)
symfony/http-kernel suggests installing symfony/dependency-injection (2.1.*)
symfony/http-kernel suggests installing symfony/finder (2.1.*)
silex/silex suggests installing symfony/browser-kit (2.1.*)
silex/silex suggests installing symfony/css-selector (2.1.*)
silex/silex suggests installing symfony/dom-crawler (2.1.*)
Writing lock file
Generating autoload files
 

Et où l'on retrouve un nouveau répertoire vendor/

Image non disponible

II-C. Autoloader

Ce qui est intéressant à regarder dans tous ces nouveaux fichiers et répertoires, c'est l'autoloader qui est pris en charge intégralement par "Composer".

II-C-1. vendor/composer/autoload_namespaces.php

 
Sélectionnez

<?php

// autoload_namespaces.php generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
    'Symfony\\Component\\Routing' => $vendorDir . '/symfony/routing/',
    'Symfony\\Component\\HttpKernel' => $vendorDir . '/symfony/http-kernel/',
    'Symfony\\Component\\HttpFoundation' => $vendorDir . '/symfony/http-foundation/',
    'Symfony\\Component\\EventDispatcher' => $vendorDir . '/symfony/event-dispatcher/',
    'Silex' => $vendorDir . '/silex/silex/src/',
    'SessionHandlerInterface' => $vendorDir . '/symfony/http-foundation/Symfony/Component/HttpFoundation/Resources/stubs',
    'Pimple' => $vendorDir . '/pimple/pimple/lib/',
);

III.

Nous allons maintenant pouvoir commencer notre projet, en continuant sa mise en place.

III-A. index.php

Dans le répertoire public, créons notre fichier d'entrée le "index.php" et faisons-le pointer sur le fichier structure de notre application.

 
Sélectionnez

<?php
require_once __DIR__ . '/../App/bootstrap.php';

Et tant que nous y sommes, créons le fichier .htaccess (pour Apache) qui va bien :

 
Sélectionnez

<IfModule mod_rewrite>
    Options -MultiViews
    RewriteEngine On
    #RewriteBase /path/to/app
    RewriteCond %{REQUEST_FILENAME} !-f
    #RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^ index.php [L]
</ IfModule>

III-B. bootstrap.php

Nous avons vu dans le index.php, que nous faisions appel à un fichier de configuration nommé bootsrap.php dans notre répertoire, c'est dans ce fichier que nous allons mettre en place la mécanique pour faire fonctionner le framework.
Construisons-le pas à pas.

 
Sélectionnez


<?php

//On initialise le timeZone
ini_set('date.timezone', 'Europe/Brussels');

//On ajoute l'autoloader
$loader = require_once __DIR__ . '/../vendor/autoload.php';

//dans l'autoloader nous ajoutons notre répertoire applicatif 
$loader->add("App",dirname(__DIR__));


//Nous instancions un objet Silex\Application
$app = new Silex\Application();

//en dev, nous voulons voir les erreurs
$app['debug'] = true;

//On lance l'application
$app->run();

Il ne nous reste plus qu'à lancer notre appli sur http://localhost/SilexApplication/public/
Nous tombons sur une belle erreur.

Image non disponible

Cette erreur prouve que notre application est bien configurée.
Silex nous réclame une route, normal, il dit « je vais où moi ? » et dans ce que vous pourrez trouver sur le net, à partir d'ici les façons de faire divergent.
Dans notre cas, on va dire au boostrap où allez voir, dans quel contrôleur nous allons.
C'est dans le(s) contrôleur(s) que nous allons définir nos routes.
Dans le bootsrap.php ajoutons la ligne suivante :

 
Sélectionnez

....
//On indique  allez pour le chemin http://localhost/SilexSkeleton/public/
$app->mount("/", new App\Controller\IndexController());

//On lance l'application
$app->run();

III-C. App/Controller/IndexController.php

Dans notre IndexController.php, nous allons définir trois méthodes (juste pour l'exemple) :

  • index ;
  • info ;
  • connect.

C'est dans la méthode connect que nous définirons nos routes.
Soit dans le fichier IndexController.php, définissons notre namespace :

 
Sélectionnez

<?php
namespace App\Controller {

}

Ajoutons les namespaces dont nous avons besoin pour faire prendre le tout.

 
Sélectionnez

<?php
namespace App\Controller {

    use Silex\Application;
    use Silex\ControllerProviderInterface;
}

Créons notre classe étendue de ControllerProviderInterface :

 
Sélectionnez

<?php
namespace App\Controller {

    use Silex\Application;
    use Silex\ControllerProviderInterface;


    class IndexController implements ControllerProviderInterface
    {
    }
}
 

Nous allons écrire notre première méthode, qui va définir nos routes.
Il est bon de savoir que dans chaque contrôleur c'est la méthode connect() qui définira vos routes, donc soit vous la définissez une fois dans IndexController, soit vous la définissez dans chaque contrôleur, ce qui est l'option que j'ai prise.

 
Sélectionnez

       public function connect(Application $app)
        {
            // créer un nouveau controller basé sur la route par défaut
            $index = $app['controllers_factory'];
            $index->match("/", 'App\Controller\IndexController::index');
            $index->match("/info", 'App\Controller\IndexController::info');
            return $index;
        }

Dans cette méthode qui prend en paramètre l'application Silex, nous récupérons la factory des contrôleurs et lui ajoutons deux routes :

  • http://localhost/SilexSkeleton/public/ ;
  • http://localhost/SilexSkeleton/public/info.

Ces deux routes font appel à deux méthodes de notre IndexController.
Définissons ces deux méthodes.

 
Sélectionnez

 public function index()
{ 
    return 'Bonjour';
}


public function info()
{
    return phpinfo();
}

Ce qui nous donne le contrôleur complet suivant :

 
Sélectionnez

<?php
namespace App\Controller {

    use Silex\Application;
    use Silex\ControllerProviderInterface;


    class IndexController implements ControllerProviderInterface
    {


        public function index()
        {  return 'Bonjour';
        }


        public function info()
        {
            return phpinfo();
        }

        public function connect(Application $app)
        {
            // créer un nouveau controller basé sur la route par défaut
            $index = $app['controllers_factory'];
            $index->match("/", 'App\Controller\IndexController::index');
            $index->match("/index", 'App\Controller\IndexController::index');
            $index->match("/info", 'App\Controller\IndexController::info');



            return $index;
        }


    }

}

Maintenant, si nous allons sur le lien suivant http://localhost/SilexSkeleton/public, cela affichera « bonjour ».
Tandis que le lien http://localhost/SilexSkeleton/public/info, vous affichera le phpinfo().

III-D. Conclusion

Potentiellement l'application est fonctionnelle en l'état et vous n'avez besoin de rien d'autre pour développer votre application.
Mais nous allons encore faire un petit pas plus loin.

IV.

Twig est un moteur de templates PHP permettant de séparer la couche de présentation de vos applications web, tout en gardant flexibilité, rapidité et facilité au développement.
L'objectif principal de Twig est de proposer aux développeurs de séparer la couche de présentation (Vue du MVC) dans des templates dédiés, afin de favoriser la maintenabilité du code. Idéal aussi pour les graphistes qui ne connaissent pas forcément le langage PHP et qui s'accommoderont parfaitement des instructions natives du moteur, relativement simples à maîtriser.
Vous trouverez toute la doc et des exemples sur leur site.

IV-A. Installation

Pour installer Twig, nous allons utiliser "Composer", mais vous devez savoir que SensioLabs a également compilé en C cette bibliothèque et que donc on peut l'intégrer nativement à PHP (voir ici), cette compilation permettra aux très gros projets de gagner de la vélocité.
Installation de Twig, d'abord modifier le fichier composer.json, pour ajouter Twig :

 
Sélectionnez

{
    "minimum-stability":"dev",
    "require":{
        "silex/silex":"1.0.*",
        "symfony/twig-bridge":"2.1.*",
        "twig/twig":">=1.8,<2.0-dev"
       
    }

}

Suivi de la commande :

 
Sélectionnez
php composer.phar update

IV-B. bootstrap.php

Dans le boostrap, nous allons initialiser Twig, en donnant comme paramètre le répertoire par défaut et le cache.

 
Sélectionnez

/* twig */
$app->register(new Silex\Provider\TwigServiceProvider(), array(
    "twig.path" => dirname(__DIR__) . "/App/Views",
    'twig.options' => array('cache' => dirname(__DIR__).'/cache', 'strict_variables' => true)
));

On voit bien ici, on dit à Twig d'aller chercher les vues dans /App/Views.

IV-C. layout.twig

Dans App/Views, créez un fichier layout.twig qui sera la vue de base de notre application et dedans nous aurons ceci :

 
Sélectionnez

{# layout principal #}
<!doctype html>

<html lang="fr-FR">
<head>
    <meta charset="UTF-8">
    <title>SilexSkeleton</title>


</head>
<body>
<header>

    <div id="content">

        {% block content %}
        {% endblock %}

    </div>
</header>

<footer>

</footer>

</body>
</html>

Bon actuellement cela ne change rien, mais revenons dans notre IndexController et modifions quelque peu notre méthode index.

IV-D. IndexController.php

 
Sélectionnez

public function index(Application $app)
{
   return $app["twig"]->render("index/index.twig");
}

Ici nous avons modifié deux choses, nous avons d'abord mis l'application en paramètre afin de pouvoir rechercher Twig.
Ensuite, nous avons donné le chemin d'une vue dans la méthode render, ce chemin est App/Views/index/index.twig.

IV-E. index.twig

Il suffit dans ce fichier de mettre le code suivant :

 
Sélectionnez

{% extends "layout.twig" %}

{% block content %}

    Bonjour ! de ma vue Twig

{% endblock %}

Concrètement si vous allez sur le lien http://localhost/SiteSilex/public, cela ne change pas grand-chose, mais si vous regardez le code source :

 
Sélectionnez

<!doctype html>

<html lang="fr-FR">
<head>
    <meta charset="UTF-8">
    <title>SilexSkeleton</title>


</head>
<body>
<header>

    <div id="content">

        
    Bonjour ! de ma vue Twig


    </div>
</header>

<footer>

</footer>

</body>
</html>

Nous avons bien une page HTML complète, je vous renvoie sur la doc de Twig pour comprendre la gestion des 'extends' et 'block' de Twig.

V.

V-A. Mise en page

Ici nous allons mettre en place le Bootstrap de Twitter, pourquoi ? Juste pour pouvoir avoir un peu de mise en page et puis c'est une bonne excuse pour parler de la génération de routes.

V-A-1. Routes

Dans notre controller, nous avons généré les routes dans la méthode connect(), mais nous allons "binder" ces routes et les récupérer dans d'autres contextes.

V-A-2. bootstrap.php

Il faut ajouter la ligne suivante dans le bootstrap.php :

 
Sélectionnez

# url generator
$app->register(new Silex\Provider\UrlGeneratorServiceProvider());

Grâce à ce provider, nous allons pouvoir utiliser deux méthodes :

  • url() ;
  • path().

Mais avant nous devons "binder" les routes dans notre controller

 
Sélectionnez

        public function connect(Application $app)
        {
            // créer un nouveau controller basé sur la route par défaut
            $index = $app['controllers_factory'];
            $index->match("/", 'App\Controller\IndexController::index')->bind("index.index");
            $index->match("/info", 'App\Controller\IndexController::info')->bind("index.info");



            return $index;
        }

Il ne reste plus qu'à télécharger le bootstrap Twitter et l'installer dans /public, je vous mets également une petite css perso pour finaliser :

 
Sélectionnez

body
{
    margin-top: 70px;
}
html
{
    position: relative;
}

body
{
    font: 11px Verdana, Arial, Helvetica, sans-serif;
    background-color: #efefef;
    /* margin:1px;
    padding:0px;*/

}


footer
{
    background-color: #F5F5F5;
    border-top: 1px solid #E5E5E5;
    margin-top: 70px;
    padding: 70px 0;
}

.pull-center
{
    text-align: center;
}

#content
{
    width: 75%;
    margin-left: auto;
    margin-right: auto;
    padding: 5px;
    border: 1px solid #cccccc;
    margin-top: 20px;
    background-color: white;
    position: relative;
    z-index: 3;
}

#content form label
{
    display: block;
    width: 300px;
    background-color: #B9ED5D;
    float: left;
    text-align: right;
    line-height: 2.1em;
    padding: 0 0.8em 0 0;
    margin-right: 3px;
}

#content form input
{
    border: 1px solid #cccccc;
    width: 250px;
    -webkit-border-radius:3px;
    -moz-border-radius:3px;
    border-radius:3px;
}




#content form input[type=checkbox]
{
    display: inline;
    width: 15px;
}

V-B. layout.twig

Je vous mets ici le code avec l'intégration du bootstrap Twitter, regardez de plus près les méthodes path() et url() :

 
Sélectionnez

{# layout principal #}
<!doctype html>

<html lang="fr-FR">
<head>
    <meta charset="UTF-8">
    <title>SilexSkeleton</title>
    <link rel="stylesheet" href="{{ url('index.index') }}bootstrap/css/bootstrap.css">
    <link rel="stylesheet" href="{{ url('index.index') }}bootstrap/css/bootstrap-responsive.css">
    <link rel="stylesheet" href="{{ url('index.index') }}bootstrap/css/bootstrap-notify.css">
    <link rel="stylesheet" href="{{ url('index.index') }}css/default.css">

    <script type="text/javascript" src="{{ url('index.index') }}bootstrap/js/bootstrap.js"></script>
    <script type="text/javascript" src="{{ url('index.index') }}bootstrap/js/bootstrap-dropdown.js"></script>
    <script type="text/javascript" src="{{ url('index.index') }}bootstrap/js/bootstrap-transition.js"></script>
    <script type="text/javascript" src="{{ url('index.index') }}bootstrap/js/bootstrap-scrollspy.js"></script>
    <script type="text/javascript" src="{{ url('index.index') }}bootstrap/js/bootstrap-modal.js"></script>
    <script type="text/javascript" src="{{ url('index.index') }}bootstrap/js/bootstrap-tab.js"></script>


</head>
<body>
<header>
    <body data-spy="scroll" data-target=".navbar">

    <div class="navbar navbar-inverse navbar-fixed-top">
        <div class="navbar-inner"><section id="I-F" noNumber="1">

            <div class="container">
                <a class="brand" href="#">SilexSkeleton</a>

                <div class="nav-collapse collapse">
                    <p class="navbar-text pull-right">

                        <b>Nous sommes le {{ "now"|date("d/m/Y") }} </b>
                    </p>
                    <ul class="nav" role="navigation">
                        <li><a href="{{ path("index.index") }}">Accueil</a></li>
                        <li><a href="{{ path("index.info") }}">Info</a></li>

                    </ul>
                </div>
            </div>
        </div>
    </div>


</header>
<div id="content">

    {% block content %}
    {% endblock %}

</div>

<footer>

</footer>

</body>
</html>

VI. La suite....

C'est ici que se termine cet article sur Silex.
J'espère que je vous ai montré avec quelle facilité il est possible de monter un projet en Silex, prochainement je développerai cet article avec les notions de Session, Base de données, Formulaire et Validation.
Ce qui est bien avec Silex, c'est qu'il est une bonne porte d’entrée vers Symfony2, parce qu'inévitablement, plus le projet Silex est gros, plus on lorgne vers Symfony.

VII. Remerciement

Je profite de l'espace qui m'est donné pour remercier ClaudeLELOUPpour sa relecture. Ainsi que grunk pour ses remarques judicieuses.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2012 Ernaelsten Gérard. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.