28 avril 2014

PHP - Introduction à Symfony


Symphony 2 est un framework qui permet de réaliser des applications Web en PHP.
Doctrine 2 est un framework qui permet la persistance d'objets en base de données relationnelle.

Cet article présente les concepts et l'organisation des projets PHP avec Symphony 2 et Doctrine 2.

Organisation des fichiers

  • /app :
    • contient les fichiers de configuration, de cache, de logs, etc.
  • /src :
    • contient le code source
  • /web :
    • pages HTML, CSS, JavaScript
    • fichier frontal : /web/app.php
  • /vendor :
    • bibliothèques externes :
      • Symfony 2
      • Doctrine : Framework de persistance
      • Twig
      • SwiftMailer : Envoi de mails

Contrôleur frontal (Front controller)

C'est le point d'entrée de l'application.

Il y a deux contrôleurs frontaux : un pour l'environnement de production et un pour l'environnement de développement.
  • Fichier : 
    • /app/app.php : environnement de production
    • /app/app_dev.php : environnement de développement

Bundle

Un bundle sert à découper le code source en fonctionnalités.

Ceci permet de réutiliser des bundles existants, voir le site : http://knpbundles.com/

Structure d'un bundle

Un Bundle contient :
  • /Controller : les contrôleurs
  • /Entity : les modèles
  • /Form : les formulaires
  • /Resources
    • /config : fichiers de configuration
    • /public : CSS, JavaScript, Images
    • /views : Les vues : templates Twig
  • /Tests : Tests unitaires et fonctionnels
  • /DependencyInjection

Créer un bundle

Lancer la commande suivante pour créer un Bundle :
php app/console generate:bundle
Saisir les différentes informations pour la création de ce bundle, notamment :
  • Namespace : Nom du bundle
  • Répertoire du bundle

Routeur

Le routeur définit les URIs d'accès aux différentes pages de l'application.
  • Fichier : config/routing.yml

Contrôleur, Modèle et Vue

Symfony 2 repose sur le pattern MVC.

Contrôleur

Le contrôleur retourne une réponse à partir d'une requête :
  • Request : Requête HTTP
  • Response : Réponse

Exemple : Récupérer l'identifiant de l'élément à modifier depuis l'URL


  • Fichier de routes : Resources/config/routing.yml
book_edit:
    path:      /book/{id}
    defaults:  { _controller: BookBundle:Book:edit }
    requirements:
        id:  \d+
  • Contrôleur : Controller/BookController.php
    • Récupérer l'id du livre contenu dans l'URL
<?php
namespace demo\BookBundle\Controller;

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

class BookController extends Controller
{
  public function edit($id)
  {
    return new Response("Edit book with id : ".$id.".");
  }
}

Nous pouvons aussi récupérer des informations du Request depuis le contrôleur, via :
$this->getRequest()

Vue : templates Twig

  • Extension de fichier des templates Twig : [page].html.twig
Les templates Twig sont des pages HTML avec des expressions de type :
{{ object.property }}
et
{% if condition %} ... {% endif %}


Les commentaires sont de la forme :
{# commentaire #}

Appeler un template depuis le contrôleur

class BookController extends Controller
{
  public function view()
  {
    return $this->render('BookBundle:Blog:book.html.twig');
  }
}

Services

Les services sont définis via les bibliothèques externes définies dans le répertoire vendor.

Nous pouvons utiliser ces services dans les contrôleurs.

Pour récupérer un service :
$this->get('nom_du_service')
Voici la liste des services par défaut :
  • $this->get('request') ou $this->getRequest():
    • Requête HTTP (Objet Request)
  • $this->get('session') :
    • Session HTTP
Autres services :
  • $this->get('templating') ou $this->getRender() :
    • Appel au moteur de template Twig pour le rendu
  • $this->get('mailer') :
    • Envoi des mails via SwiftMailer
  • $this->get('doctrine') ou $this->getDoctrine() :
    • Accès au framework de persistance Doctrine
La commande suivante permet de récupérer la liste des services disponibles :
php app/console container:debug

Pour bien découper le code source, il est recommandé de définir ses propres services.

Persistance des données : Doctrine 2

Doctrine 2 est un framework de persistence de type ORM.

Il gère les entités Entity via des Entity Manager et des Repository.

Service

Doctrine est accessible depuis un service ou un contrôleur via :
$this->getDoctrine()

Paramétrage de la base de données

  • Fichier : app/config/parameters.yml
parameters:
    database_driver:   pdo_mysql
    database_host:     localhost
    database_port:     ~
    database_name:     database_name
    database_user:     root
    database_password: ~
La commande suivante permet de créer la base de données depuis Symfony :
php app/console doctrine:database:create
Pour générer le script de mise à jour des tables dans la base de données depuis les informations des entités définies dans l'application :
php app/console doctrine:schema:update --dump-sql
Pour forcer la mise à jour des tables en base de données sans avoir à passer le script sql généré :
php app/console doctrine:schema:update --force

Connexion à la base de données

Pour récupérer la connexion à la base de données par défaut :
$this->getDoctrine()->getConnection()
Dans le cas où il y a plusieurs bases de données dans le paramétrage, il faut alors spécifier le nom de la base de données défini dans database_name :
$this->getDoctrine()->getConnection("database_name")

Entity Manager (Gestionnaire d'entités)

L'Entity Manager contient les entités à persister et gère leur persistance en base de données.

L'Entity Manager est liée à une base de données.

Pour récupérer l'Entity Manager de la base de données par défaut :
$this->getDoctrine()->getManager()

Pour récupérer l'Entity Manager d'une base de données en particulier :
$this->getDoctrine()->getManager("database_name")

Méthodes de l'Entity Manager

Ces méthodes permettent de gérer les entités à persister et les modifications à effectuer en base :
  • flush : appliquer les modifications à effectuer en base de données
  • clear : annuler les modifications à effectuer en base de données
  • persist($entity) : persister une nouvelle entité ou une entité existante
  • remove($entity) : supprime l'entité en base de données
  • detach($entity) : annuler les modifications à effectuer en base de données pour une entité en particulier
  • contains($entity) : indique si l'Entity Manager contient l'entité dans la liste des entités à persister
  • refresh($entity) : met à jour l'objet $entity d'après les informations en base. Ceci annule toutes les modifications effectuées sur cette objet

Repository

Le Repository est une DAO dédiée à une entité en particulier.

Elle est instanciée dynamiquement via l'appel de la méthode getRepository de l'Entity Manager :
$em->getRepository("BookBundle:Book")

Le Repository offre les méthodes suivantes :
  • find($id) : retourne l'entité d'identifiant $id
  • findAll : retourne les entités
  • findByXxx : retourne les entités selon la valeur de leur propriété Xxx
  • findOneByXxx : une seule entité en résultat
  • findBy : sélectionne les entités selon un tableau de critères
  • findOneBy : un seule entité en résultat

Entité

Une entité est définie via des annotations à la syntaxe particulière dans les commentaires.
/**
 * @ORM\Entity
 * @ORM\Entity(repositoryClass="Demo\BookBundle\Entity\BookRepository")
 * @ORM\Table(name="book")
 */
class Book { ... }
, avec :
  • @ORM\Entity : Classe de l'entité
  • @ORM\Table : Table de la base de données
L'identifiant :
  /**
   * @ORM\Column(name="id", type="integer")
   * @ORM\Id
   * @ORM\GeneratedValue(strategy="AUTO")
   */
  private $id;
, avec :
  • @ORM\Column : Colonne de la table en base de données
  • @ORM\Id : Table de la base de données
  • @ORM\GeneratedValue : Valeur générée automatiquement
La propriété title :
  /**
   * @ORM\Column(name="title", type="string", length=200)
   */
  private $title;
, avec :
  • @ORM\Column : Colonne de la table en base de données
    • type="string" : le type est celui de Doctrine. Il y a une correspondance entre les types de Doctrine avec les types SQL et les types PHP (consulter la documentation de Doctrine pour avoir cette correspondance)

Générer une entité

La commande suivante permet de créer et générer une nouvelle entité via une série de questions/réponses en ligne de commandes :
php app/console generate:doctrine:entity
Pour générer les getters/setters des propriétés de l'entité :
php app/console doctrine:generate:entities BookBundle:Book

Références