Symfony

Posted by IT NISRO 0 commentaires

 Symfony est un Framework PHP, crée par la société SensioLabs en 2005.

Il a été inventé par des français et est totalement open source et gratuit.
Il utilise une architecture MVC ce qui permet un meilleur travail d'équipe et une meilleur distribution du travail. De plus il fonctionne avec un ORM.
Il est utilisé par de nombreuses sociétés et par nombreux outils tel que : Drupal, PhpBB ou encore Laravel.

Pourquoi choisir un Framework ?

Un Framework permet :

  • Un gain de productivité : il implétente beaucoup de fonctionalitées basiques et rend les opérations native plus simple.
  • Un code bien structuré : il utilise de nombreux patterns et des architectures très connues telles que MVC
  • De disposer de nombreux outils : il permet de gérer des formulaires, des utilisateurs… de façon simple
  • D'améliorer la façon de travailler : il permet le travail d’équipe, le découpage et la séparation entre les développeurs PHP et le designer. Permet la reprise de code par d’autres developpeurs.
  • D'obtenir de l'aide et des mises à jours : Cours, tutoriaux, aide sur les forums, mis à jour régulièrement avec souvent un support à long terme.

Structure

L'architecture MVC

L'architecture MVC de Symfony peu être représentée de cette façon :

Lorsqu'un client demande une URL, celle-ci est d'abord traitée par le controleur fontrale de Symfony avant d'être envoyée au noyaux.
Quand le noyaux reçois la demande d'une URL, il appel le service de routing, celui-ci va alors lui indiquer le contrôleur à appeler pour l'URL que le client demande.
Le noyaux appel alors le contrôleur qui va si il en a besoin, appeler le modèle et générer la vue.
Quand le contrôleur a fini que générer la vue, il retourne le résultat au noyaux, celui-ci va alors transmettre la réponse au client.

Les ORM

ORM signifie Object Relational Mapping. Il permet de créer l'illusion d'une base de données orientée objet à partir d'une base de données relationnelle, en transformant l'ensemble des relations en objet.
Il existe deux types d'ORM :

  • Data Mapped (Doctrine) : Permet une abstraction plus puissante avec la base de données, on envoie l’objet à un manager pour le sauvegarder en base de données.
  • Active Record (Propel) : Un objet est une ligne de la base de données, chaque champs est une colonne, la méthode save() est présente sur chaque objet.
Data mappedActive record
$user = new User;
$user->setName('Antoine');
EntityManager::persist($user);
$user = new User;
$user->setName('Antoine');
$user->save();

Doctrine permet d'avoir une abstraction plus forte avec la base de données afin d'éviter les problèmes de couplage fort. Cependant cette abstraction a un prix sur ses performances, en effet le manager d'entité est lourd comparé au patterns active record qui contient le code de persistance directement de la classe concernée. Le pattern active record est très intéressant dans le cas d'une structure CRUD.

Voici un exemple de requêtes Doctrine :

$this->getUserRepository()
           ->createQueryBuilder('u')
           ->select('u, p')
           ->leftJoin('u.profile', 'p')
           ->where('u.login = :login')
           ->setParameter('login', 'b.rossi')
           ->getQuery();

Doctrine génère alors le code SQL suivant :

SELECT * FROM  user u LEFT JOIN lnk_user_profile lup ON u.id = lup.user_id LEFT JOIN profile p ON lup.profile_id = p.id WHERE u.login = 'b.rossi';

L'arborescence

L'arborescence d'un projet Symfony est la suivante :

			.
			├── app
			│   ├── config (Contient la configuration générale de l’application Symfony : Connexion à la base de donnée, Routing général, Configuration de la sécurité et du firewall, Configuration générale (mail, ORM…))
			│   └── Resources (Contient les ressources générales de l’application Symfony : Les fichiers de traduction, La vue de base)
			├── bin (Contient l’executable Symfony et Doctrine)
			├── src (Contient les bundles de chaque projet)
			│   └── Dms
			│       ├── ClaimBundle
			│       ├── CoreBundle
			│       └── PlanningBundle
			├── var (Contient les fichiers de cache et les fichiers de log)
			│   ├── cache
			│   └── logs
			├── vendor (Contient les librairies utilisées dans Symfony)
			│   ├── composer
			│   ├── doctrine
			│   ├── swiftmailer
			│   ├── symfony
			│   └── twig
			└── web (Contient les fichiers js / css / images pour chaque bundle (une fois généré))
			    └── bundles
         ├── dmsclaim          ├── dmscore    └── dmsplanning

Fonctionnement

Les bundles

Un bundle est un répertoire qui a une structure bien définie et qui peut héberger à peu près tout : des classes aux contrôleurs en passant par les ressources web (C'est une version amélirée des plugins).
Un bunble à la structure suivante :

			.
			├── Controller (Contient les contrôleurs du bundle)
			│   └── IndexController.php
			├── DependencyInjection (Contient les injections de dépendance)
			├── EventListener (Contient les listener qui vont se déclencher lors de certains évènements (ex: lors d’une requête))
			├── Resources (Contient les configurations du bundle (routes, services…))
			│   ├── config
			│   │   └── routing.yml
			│   │   └── services.yml
			│   ├── public (Contient les fichiers css / js / images)
			│   ├── translations (Contient les traductions du bundle)
			│   └── views (Contient les vues du bundle qui sont appelées par les contrôleurs)
			│       └── index.html.twig
			├── Services (Contient les services)
			└── Tests (Contient les tests)
			

Le routing et les configurations (yml, xml, php)

Le routing permet d’associer une URL à un contrôleur et à une action de celui-ci.
Il existe 4 formats d’écriture des fichiers de route:

  • Les annotations
  • Le Yaml
  • Le XML
  • Le PHP

Et 3 formats pour les fichiers de configuration:

  • Le Yaml
  • Le XML
  • Le PHP

Voici un exemple de route écrit en Annotation :

			// src/AppBundle/Controller/BlogController.php
			class BlogController extends Controller {

				/** * @Route("/blog/{culture}") */
				public function showAction($culture) {
				// …
				}

			}
		

Voici un exemple de route écrit en Yaml :

			# src/AppBundle/Resources/config/routing.yml
			blog_show:
			   path: /blog/{culture}
			   defaults: { _controller: AppBundle:Blog:show }
   				requirements:
   					culture: en|fr
		

Voici un exemple de route écrit en XML :

			<!-- src/AppBundle/Resources/config/routing.xml -->
			<?xml version="1.0" encoding="UTF-8" ?>
			<routes xmlns="http://symfony.com/schema/routing" 
					xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
					xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
			   <route id="blog_show" path="/blog/{culture}">
					<default key="_controller">AppBundle:Blog:show</default>
			   </route>
			</routes>
		

Voici un exemple de route écrit en PHP :

			// src/AppBundle/Resources/config/routing.php
			use Symfony\Component\Routing\RouteCollection;
			use Symfony\Component\Routing\Route;
			$collection = new RouteCollection();
			$collection->add('blog_show', new Route('/blog/{culture}', array('_controller' => 'AppBundle:Blog:show')));
			return $collection;
		

Les annotations et le format Yaml sont les deux formats les plus utilisés dans Symfony de par leur syntaxe simple et lisible.

Les contrôleurs

Voici un exemple de contrôleur Symfony :

			<?php
			namespace MyProject\BlogBundle\Controller;
			use MyProject\CoreBundle\Controller\Common\BaseController;
			use Doctrine\ORM\Query;
			use Symfony\Component\HttpFoundation\Request;
			class BlogController extends BaseController {
		
		    	/** * @Route("/article/{id}") */
    			public function articleAction(Request $request, $id) {
         			$culture = $request->getLocale();
			        // Requête pour récupérer l'article (on appel le modèle)
          			$article = $this->getDoctrine()->getManager()->getRepository("MyProjectBlogBundle:Article")->find($id);

          			// On appel la vue
			        return $this->render('MyProjectBlogBundle:article.html.twig', array('culture' => $culture, 'article' => $article));
    			}

			}
			?>
		

Dans cet exemple de contôleur appel le modèle pour récupérer un article puis génère la vue en lui donnant les informations qu'elle a besoin.

Les vues (Twig / PHP)

Voici un exemple de vue Twig :

			<!DOCTYPE html>
			<html>
			    <head> 
			       <title>
			           {% block title %}
			                   Blog :: 
			           {% endblock %}
			       </title>
			       {% block stylesheets %}
			           <link rel="stylesheet" href="{{ asset('bundles/myprojectblog/css/jquery.css') }}" type="text/css" />
			       {% endblock %}
			      
			       {% block javascripts %}
			           <script language="javascript" src="{{ asset('bundles/myprojectblog/js/jquery.js') }}"></script>
			       {% endblock %}
			    </head>
			    <body>
			            {% block content %}{% endblock %}
			                  {# END - BLOCK RESERVE AUX PLUGINS JQUERY UI UTILISANT LE CSS #}
			            {% block endJavascripts %}{% endblock %}
			    </body>
			</html>
		

Twig est un language simple qui permet l'héritage et l'imbracation. Sont language étant limité, cela permet d'éviter aux développeurs peu expérimentés d'écrire du code dans la partie template.
Dans l'exemple suivant, le code Twig redéfini ou surcharge les valeurs contenu dans les blocks du templates hérité (parent).

			{% extends 'MyProjectBlogBundle::layout.html.twig' %}
			{% block title %}
			    {{ parent() }} Article
			{% endblock %}
			{% block content %}
			    <h2>{{ article.title|trans }}</h>
			    <div class="content">
			       {% include('MyProjectBlogBundle:Article:content.html.twig') %}
			       {% autoescape false %}
			           {{ text }}
			       {% endautoescape %}
			    </div>
			{% endblock %}
		

Les modèles (yml, annotation, xml)

La partie modèle permet de définir la structure et les relations des objets par rapport à la base de données relationelle.
Elle peut être écrite sous forme d'annotation directement dans les classes des objets, en xml ou en Yaml.
Voici un exemple en Yaml :

			MyProject\CoreBundle\Entity\User:
		    type: entity
		    repositoryClass: MyProject\CoreBundle\Repository\UserRepository
		    table: user
		         id:
		           id:
		               type: integer
		               nullable: false
		               unsigned: false
		               id: true
		               generator:
		               		strategy: IDENTITY
		    fields:
		           login:
		               type: string
		               nullable: false
		               length: 255
		    manyToMany:
		           profile:
		               targetEntity: Profile
		               inversedBy: user
		               joinTable:
		                       name: lnk_user_profile
		                       joinColumns:
		                       		name: user_id
		                       			referencedColumnName: id
		                       inverseJoinColumns:
		                       		name: profile_id
		                       			referencedColumnName: id
		

Les formulaires

Les formulaires peuvent être crée de deux façon :

  • Avec une classe

    $mail = new Mail();
    $form = $this->createForm(new MailType(), $mail);
  • Avec un builder

    $form = $this->createFormBuilder()
               ->setAction($this->generateUrl('change_email_password'))
               ->add('email', 'repeated', array('type' => 'email'))
               ->getForm();

Les classes servent quand le formulaire est réutilisé plusieurs fois, ou lorsqu'il est lié à une entité.
Le builder est utile uniquement lorsque le formulaire est utilisé une seule fois, cela évite d'écrite trop de code.
Ce code doit être écrit dans le contrôleur et l'objet suivant doit être donnée à la vue pour qu'elle génère le formulaire :

$form->createView();

Pour afficher le formulaire voici un exemple de code à écrire dans la vue :

			{{ form_start(form, {'action': path('new_mail', {'id': 10})}) }}
			{{ form_errors(form) }}
			<div id="email">
			{{ form_label(form.email) }}
			      {{ form_widget(form.email) }}
			      {{ form_errors(form.email) }}
			</div>
			<div id="subject">
			{{ form_label(form.subject) }}
			      {{ form_widget(form.subject, {'attr': {'class': 'subject', 'title': 'Votre subjet'}) }}
			      {{ form_errors(form.subject) }}
			</div>
			<nput type="submit" />
			{{ form_end(form) }}
		

Les formulaires Symfony permettent :

  • La génération des champs manquants
  • La génération du token pour éviter les attaques CSRF
  • La génération des validateurs HTML5
  • La gestion des messages d’erreur

Afin de vérifier la valider d'un formulaire, Symfony met à disposition un sytème de validation :

			$mail = new Mail();
			$form = $this->createForm(new MailType(), $mail);
			      
			$form->handleRequest($request);
			if ($form->isValid()) {
			    // sauvegarde des éléments de votre formulaire qui ne sont pas mappés avec l'objet
			    ...
			    // sauvegarde de votre objet qui a été mis à jour par le formulaire
			    $em = $this->getDoctrine()->getManager();    $em->persist($mail);    $em->flush();

			        // redirige vers une autre page
			}

			// retourne sur la page du formulaire et affiche des messages d’erreur
		

Communauté et documentation

Communauté et documentation

Symfony dispose d'une très grosse communauté et d'une très bonne documentation.

Il existe des groupes de discussion sur google, un channel IRC, des formations payantes par les réalisateurs du Framework, des sites communautaire très actifs (stackoverflow, openclassroom…), des sites recensants les différents plugins et des outils intégrés dans les IDE tels que Netbeans.

La documentation en ligne est découpée en plusieurs parties :

  • Book : Qui permet d'appendre l'ensemble du fonctionnement de Symfony (les bases et sa structure).
  • Cookbook : Qui permet de trouver les solutions aux problèmes les plus courant (ex: envoyer un mail via google).
  • The component : Qui permet d'approfondir les connaissances sur chacun des composants de Symfony.
  • Best Practices : Qui permet d'apprendre à utiliser Somfony de la meilleur façon.

Conclusion

Conclusion

Symfony permet de faire de nombreuses choses facilement, il nécéssite cependant un temps d’apprentissage est non négligeable.
Malgré cela il est un outil de travail performant qui accroitera la productivé.
Sa grande communauté et sa documentation complete permettent une prise en main guidée et une aide en cas de problèmes.
Cepedant il reste relativement lourd (et gourmand en ressources) lors de l’exécution, il faut mettre en place APC et désactiver Xdebug afin d’avoir de bonnes performances.
Pour des petits projets il faut envisager d’utiliser des Framework tels que Laravel qui sont plus légers et beaucoup plus simples à prendre en main.


0 commentaires:

Enregistrer un commentaire

Membres

Formulaire de contact

Nom

E-mail *

Message *