Kevin Verschaeve
Quoi qu'on va faire ?
Une structure
Des composants
35 composants
Dont:
Une manière de coder
"J'ai besoin de cette lib, qui elle même a besoin de telle lib, qui elle même a besoin de telle lib, qui ... "
$ composer install
C'est tout !
On déclare les librairies dont on a besoin dans le fichier composer.json à la racine du projet
{
"require": {
"pop/lalib": "~1.0"
}
}
La commande composer install, va télécharger la librairie "pop/lalib" en version 1.0 minimum et toutes les dépendances de celle ci, puis l'installer dans le projet
$ sudo curl -LsS https://symfony.com/installer -o /usr/local/bin/symfony
$ sudo chmod a+x /usr/local/bin/symfony
Pour les gens biens (sous Linux) et les riches (Mac OS X)
=> nouvelle commande :
$ symfony
Pour ceux qui cherchent les problèmes (sous Windows)
c:\> php -r "readfile('https://symfony.com/installer');" > symfony
c:\> move symfony c:\projects
=> nouvelle commande :
c:\projects\> php symfony
$ symfony new pop 3.0
Créé un projet Symfony, avec la version 3.0 dans le dossier "pop"
$ cd pop
$ php bin/console server:run
Va dans le dossier du projet et lance un serveur
Dans le navigateur, aller sur http://localhost:8000
app/
-> fichiers de configurations, vues, ...
src/
-> le code PHP de l'application, on passe la majeure partie du temps dans ce dossier
bin/
-> fichiers exécutables, comme bin/console
tests/
-> test automatisés
var/
-> fichiers créés automatiquement (logs, cache)
vendor/
-> librairies/bundles externes téléchargés par composer
web/
-> root du projet, ici va tout ce qui est publique, css, js, images...
Configurer une base de données
Activer la traduction et régler la langue par défaut
# app/config/config.yml
# sous la clé parameters, régler la clé locale sur la langue souhaitée (ici fr)
parameters:
locale: fr
# décommenter la ligne "translator" sous la clé "framework"
framework:
translator: { fallbacks: ["%locale%"] }
# app/config/parameters.yml
parameters:
database_host: 127.0.0.1
database_port: null
database_name: pop
database_user: root
database_password: pass
Et il en a surement aussi fait un bundle
$ composer require lexik/maintenance-bundle
<?php
// app/AppKernel.php
public function registerBundles()
{
$bundles = array(
// ...
new Lexik\Bundle\MaintenanceBundle\LexikMaintenanceBundle(),
);
// ...
}
Enregistrer le bundle pour Symfony dans app/AppKernel.php
lexik_maintenance:
driver:
class: '\Lexik\Bundle\MaintenanceBundle\Drivers\ShmDriver'
Dans app/config/config.yml
# passer le site en mode maintenance
$ bin/console lexik:maintenance:lock
# passer le site en mode normal
$ bin/console lexik:maintenance:unlock
Permet de rendre du PHP dans du HTML de façon plus triviale, propre, sécurisée et facile à comprendre pour un intégrateur
avec PHP
<h1>Hello <?php echo $name; ?></h1>
avec Twig
<h1>Hello {{ name }}</h1>
avec PHP
<ul>
<?php foreach ($articles as $article): ?>
<li><?php echo $article->getName(); ?></li>
<?php endforeach; ?>
</ul>
avec Twig
<ul>
{% for article in articles if article.name is not empty %}
<li>{{ article.name }}</li>
{% else %}
Ya pas d articles
{% endfor %}
</ul>
avec PHP
<h1>Hello <?php echo strtoupper($name); ?></h1>
<p>Liste: <?php echo implode(', ', $liste); ?></p>
avec Twig
<h1>Hello {{ name|upper }}</h1>
<p>Liste: {{ liste|join }}</p>
{# index.html.twig #}
{% extends '::base.html.twig' %}
{% block title %}Index{% endblock %}
{% block body %}
Hello {{ name }} !
{% endblock %}
{# base.html.twig #}
<html>
<head>
<title>{% block title %}Fichier de base{% endblock %}</title>
</head>
<body>
{% block body %}
Le contenu par défaut
{% endblock %}
</body>
</html>
$ php bin/console doctrine:database:create
$ php bin/console doctrine:generate:entity
# AppBundle:Article
# annotation
# title, string 255, true, false
# author, string 255, false, false
$ php bin/console doctrine:schema:create
Doctrine utilise des Manager pour gérer nos entités
Ces managers fournissent des Repository qui eux fournissent des méthodes clés en main pour requeter la base de données
# dans une action de controller
public function monAction()
{
$articleRepository = $this->getDoctrine()->getRepository(Article::class);
$articles = $articleRepository->findAll();
// ce qu'on veut, avec la liste d'articles
}
$repository->findAll(); // retourne toutes les entités
$repository->find(123); // retourne l'entité avec l'id 123
$repository->findBy(['author' => 'Kevin']); // retourne la ou les entités dont l'auteur == 'Kevin'
$repository->findOneBy(...); // identique à la précédente, excepté qu'ici on ne retourne que le premier résultat
$repository->findOneByName('Kevin'); // identique à la précédente, en passant par des méthodes magiques
Quelques méthodes fournies par Doctrine
Que faire si on souhaite des requêtes plus complexes ?
<?php
namespace AppBundle\Repository;
class ArticleRepository extends EntityRepository
{
public function findFirstArticlesOfAuthor($author, $nbArticles)
{
return $this->createQueryBuilder('a')
->where('a.author = :author')
->setParameter('author', $author)
->setMaxResults($nbArticles)
->getQuery()
->getResult()
;
}
}
Le repository
Lier le repository à l'entité
/**
* @ORM\Entity(repositoryClass="AppBundle\Repository\ArticleRepository")
*/
class Article
{
// ...
}
public function monAction()
{
// ...
$myFirst5Articles = $this
->getDoctrine()
->getRepository(Article::class)
->findFirstArticlesOfAuthor('Kevin', 5)
;
// ...
}
Pour requêter, ex dans un controller
Dans le dossier AppBundle\Form, créer un fichier nommé ArticleType.php
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
class ArticleType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', TextType::class)
->add('author', TextType::class)
->add('submit', SubmitType::class)
;
}
}
Le titre de mon article est obligatoire et ne doit pas dépasser 60 caractères
Le nom de l'auteur est aussi obligatoire et ne doit pas contenir de chiffre
<?php
namespace AppBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
class Article
{
// ...
/**
* @ORM\Column(type="string", length="60", nullable=false)
* @Assert\NotBlank()
* @Assert\Length(max=60, message="Le titre de l'article ne doit pas contenir plus de 60 caractères")
*/
private $title;
/**
* @ORM\Column(type="string", nullable=false)
* @Assert\NotBlank()
* @Assert\Regexp("[a-zA-Z]", message="Le nom de l'auteur ne doit pas contenir de caractères spéciaux")
*/
private $author;
// getters and setters
// ...
}
Dans le controller
<?php
namespace AppBundle\Controller;
class ArticleController extends Controller
{
/**
* @Route("/article/new", name="article_new")
*/
public function newAction(Request $request)
{
$form = $this->createForm(ArticleType::class, new Article());
if ($form->handleRequest($request)->isValid()) {
$article = $form->getData();
$manager = $this->getDoctrine()->getManagerForClass(Article::class);
$manager->persist($article);
$manager->flush();
return new RedirectResponse($this->generateUrl('article_show', [
'id' => $article->getId(),
]));
}
return $this->render(':article:new.html.twig', [
'form' => $form->createView(),
]);
}
}
services:
app.my_project.calculator:
class: 'AppBundle\Services\Calculator'
Dans app/config/services.yml
<?php
namespace AppBundle\Services;
class Calculator
{
public function add($a, $b)
{
return $a + $b;
}
}
Dans src/AppBundle/Services/Calculator.php
Dans une action de controller
<?php
// ...
public function helloAction($name)
{
// ...
$calculator = $this->container->get('app.my_project.calculator');
// ou, $this->get('...');
$result = $calculator->add(5, 5);
return $this->render(':default:hello.html.twig', [
// ...
'result' => $result
]);
}
Puis afficher le résultat dans la vue
Activer la traduction
# app/config/config.yml
# décommenter la ligne
translator: { fallbacks: ["%locale%"] }
# En PHP
$this->get('translator')->trans('translation_key');
# En Twig
{{ 'tranlsation_key'|trans }}
# app/Resources/translation/messages.fr.yml
translation_key: Le texte affiché en français
Le nom des fichiers de traduction doivent se nommer de cette manière: <domain>.<locale>.<loader>
ex: messages.fr.yml
Locale: La langue dans laquelle on écrit la traduction
Loader: le type de format qu'on souhaite utiliser pour les traductions
Les différents loader supportés par Symfony sont:
Chacun des formats a ses avantages et inconvénients
Exercice