Lior CHAMLA
Je suis formateur dans les technologies du Web depuis 2009 : HTML, CSS, Javascript, jQuery, PHP, Programmation Orientée Objets, etc
Symfony est un framework PHP créé par des Français (SensioLabs, Cocorico !) qui est un des plus populaire sur le langage PHP.
Il est Open Source et bénéficie d'une très grande communauté.
Comme tous les Framework il offre un grand nombre d'outils et un cadre de travail pour la création de sites et d'applications web :
Avec Symfony, on travaille sur des Bundles qui sont des morceaux d'application (des modules)
Chaque bundle apporte ses propres fonctionnalités
Comme beaucoup de Framework actuellement, le parti pris est d'assister le plus possible les développeurs à l'aide d'outils console qui génèrent du code automatiquement
On peut bien entendu tout coder à la main ;-)
Le contrôleur permet d'écouter la requête (Request) d'un utilisateur et afin de créer et de renvoyer une réponse (Response)
La réponse peut être une vue HTML, JSON, XML, le téléchargement d'un fichier, une redirection, etc
Suivant le pattern MVC, votre contrôleur peut avoir recours à la base de données afin de lire ou d'écrire des données avant de renvoyer sa réponse.
Routage : dans Symfony, on peut assigner une route (URL) à une action du contrôleur
namespace AppBundle\Controller;
use Symfony\Component\HttpFoundation\Response;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
class LuckyController
{
/**
* @Route("/lucky/number/{max}")
*/
public function numberAction($max)
{
$number = mt_rand(0, $max);
return new Response(
'<html><body>Lucky number: '.$number.'</body></html>'
);
}
}
Dans Symfony, ce qu'on appelle habituellement les models deviennent des entities (entités)
Une entité représente habituellement une table de la base de données (Produit, Article, Commentaire, etc)
Grâce à Doctrine, Symfony nous permet de faire le lien entre les entités (fichiers de code) et la base de données de façon "automatique"
Doctrine est ce qu'on appelle un ORM - Object Relational Mapping
// Une entité simple, sans mapping
// relationnel
namespace AppBundle\Entity;
class Product
{
private $name;
private $price;
}
// Une entité avec mapping relationnel
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="product")
*/
class Product
{
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\Column(type="string", length=100)
*/
private $name;
/**
* @ORM\Column(type="decimal", scale=2)
*/
private $price;
}
Symfony utilise la librairie Open Source Doctrine afin de gérer la persistance des données
C'est un ORM qui permet de manipuler les données de l'application sans "écrire de SQL", on ne fait qu'utiliser des objets
On peut donc manipuler les entités de Symfony pour accéder aux données :
Symfony utilise la librairie Open Source Twig afin de gérer les templates (gabarits, ou vues) et de produire des affichages HTML
Le contrôleur peut donc générer des vues à l'aide de fichiers appelés "templates" qui sont écrits avec la syntaxe Twig
Twig a été créé pour palier à certaines limites de la syntaxe de templating classique de PHP
La syntaxe Twig permet de faire des boucles, des conditions, et bien plus
<!-- TEMPLATE CLASSIQUE -->
<h1><?php echo $page_title ?></h1>
<ul id="navigation">
<?php foreach ($navigation as $item): ?>
<li>
<a href="<?php echo $item->getHref() ?>">
<?php echo $item->getCaption() ?>
</a>
</li>
<?php endforeach ?>
</ul>
<!-- UN TEMPLATE TWIG -->
<h1>{{ page_title }}</h1>
<ul id="navigation">
{% for item in navigation %}
<li>
<a href="{{ item.href }}">
{{ item.caption }}
</a>
</li>
{% endfor %}
</ul>
Symfony offre un système de routage qui permet de gérer facilement la ré-écriture d'urls
L'idée est de fournir un outil qui permette facilement d'avoir de belles URL et d'indiquer quelles actions elles visent
Le Routeur de Symfony permet de :
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
class BlogController extends Controller
{
/**
* @Route("/blog", name="blog_list")
*/
public function listAction()
{
// ...
}
/**
* @Route("/blog/{slug}", name="blog_show")
*/
public function showAction($slug)
{
// $slug will equal the dynamic part of the URL
// e.g. at /blog/yay-routing, then $slug='yay-routing'
// ...
}
}
Plusieurs langages de programmations utilisent les annotations qui permettent de spécifier des méta-données (informations supplémentaires) concernant des variables, fonctions, classes, etc
Symfony utilise les annotations de PHP dans pas mal de situations :
/**
* @Route("/blog", name="blog_list")
*/
public function listAction()
{
// ...
}
Globale :
https://symfony.com/doc/current/index.html
Controllers :
https://symfony.com/doc/current/controller.html
Templates Twig :
https://symfony.com/doc/current/templating.html
Entités et Repositories :
https://symfony.com/doc/current/doctrine.html
Routage :
// A écrire dans src/AppBundle/Controller/LuckyController.php
namespace AppBundle\Controller;
use Symfony\Component\HttpFoundation\Response;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
class LuckyController
{
/**
* @Route("/lucky/number/{max}")
*/
public function numberAction($max)
{
$number = mt_rand(0, $max);
return new Response(
'<html><body>Lucky number: '.$number.'</body></html>'
);
}
}
// A la fin d'une fonction du controller, on peut générer un affichage
// à partir d'un template
// génère le template qui se trouve dans
// app/Resources/views/lottery/lucky/number.html.twig
// en lui passant la donnée "name"
return $this->render('lottery/lucky/number.html.twig', array(
'name' => $name,
));
// Différentes façon de faire une redirection dans un controller
public function indexAction()
{
// redirect to the "homepage" route
return $this->redirectToRoute('homepage');
// do a permanent - 301 redirect
return $this->redirectToRoute('homepage', array(), 301);
// redirect to a route with parameters
return $this->redirectToRoute('blog_show', array('slug' => 'my-page'));
// redirect externally
return $this->redirect('http://symfony.com/doc');
}
// A écrire dans src/AppBundle/Entity/Product.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="product")
*/
class Product
{
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\Column(type="string", length=100)
*/
private $name;
/**
* @ORM\Column(type="decimal", scale=2)
*/
private $price;
}
// Un produit est lié à une catégorie
// A écrire dans src/AppBundle/Entity/Product.php
{
/**
* @ORM\ManyToOne(targetEntity="Category", inversedBy="products")
* @ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
private $category;
}
// Une catégorie est liée à plusieurs produits
// A écrire dans src/AppBundle/Entity/Category.php
use Doctrine\Common\Collections\ArrayCollection;
class Category
{
/**
* @ORM\OneToMany(targetEntity="Product", mappedBy="category")
*/
private $products;
public function __construct()
{
$this->products = new ArrayCollection();
}
}
// A écrire danssrc/AppBundle/Controller/DefaultController.php
// ...
use AppBundle\Entity\Product;
use Symfony\Component\HttpFoundation\Response;
// ...
public function createAction()
{
$product = new Product();
$product->setName('Keyboard');
$product->setPrice(19.99);
$product->setDescription('Ergonomic and stylish!');
$em = $this->getDoctrine()->getManager();
// dit à Doctrine qu'on va vouloir sauvegarder ce produit (mais ne le fait pas encore)
$em->persist($product);
// déclenche l'enregistrement i.e. the INSERT query)
$em->flush();
return new Response('Saved new product with id '.$product->getId());
}
// A écrire danssrc/AppBundle/Controller/DefaultController.php
public function showAction($productId)
{
// On veut récupérer le produit qui a l'identifiant $productId
$product = $this->getDoctrine()
->getRepository('AppBundle:Product')
->find($productId);
if (!$product) {
throw $this->createNotFoundException(
'No product found for id '.$productId
);
}
// ... do something, like pass the $product object into a template
}
// Certaines choses qu'on peut faire avec le repository
$repository = $this->getDoctrine()->getRepository('AppBundle:Product');
// query for a single product by its primary key (usually "id")
$product = $repository->find($productId);
// dynamic method names to find a single product based on a column value
$product = $repository->findOneById($productId);
$product = $repository->findOneByName('Keyboard');
// dynamic method names to find a group of products based on a column value
$products = $repository->findByPrice(19.99);
// find *all* products
$products = $repository->findAll();
// query for a single product matching the given name and price
$product = $repository->findOneBy(
array('name' => 'Keyboard', 'price' => 19.99)
);
// query for multiple products matching the given name, ordered by price
$products = $repository->findBy(
array('name' => 'Keyboard'),
array('price' => 'ASC')
);
# Créer un projet Symfony grâce à Composer
composer create-project symfony/framework-standard-edition mon-projet
# Lancer le serveur web pour le projet
cd mon-projet
php bin/console server:run
# Générer un nouveau bundle
php bin/console generate:bundle
# Générer une entité Doctrine
php bin/console doctrine:generate:entity
# Générer les getters et setters pour une entité existante (Product)
php bin/console doctrine:generate:entities AppBundle/Entity/Product
# Demander à Doctrine de créer/modifier les tables correspondantes
php bin/console doctrine:schema:update --force
By Lior CHAMLA
Petite introduction au framework le plus hype de PHP : Symfony (fonctionnement, notions, dépendances etc)
Je suis formateur dans les technologies du Web depuis 2009 : HTML, CSS, Javascript, jQuery, PHP, Programmation Orientée Objets, etc