Vous êtes sur la page 1sur 12

LARAVEL OU SYMFONY

Installation
Dans les 2 cas l'installation peut se faire au travers de la commande create-
project de composer.

# Laravel
composer create-project laravel/laravel example-app

# Symfony
composer create-project symfony/skeleton:"6.3.*" my_project_directory
cd my_project_directory
composer require webapp

Symfony nécessite plusieurs commande car il s'installe en mode "microservice" par


défaut en n'incluant que le strict minimum. La commande composer require
webapp permet d'installer tous les composants nécessaire à la création d'une
application web classique.

On notera aussi que les 2 frameworks intègre une commande (laravel pour Laravel
et symfony pour Symfony) que l'on peut utiliser pour piloter le framework et faire
certaines tâches (initialiser un projet par exemple).

Structure
La structure des 2 frameworks est similaire avec la présence d'un dossier public qui
servira de racine au serveur HTTP. Les sources sont placé dans un dossier src pour
Symfony et app dans le cas de Laravel. Dans les 2 cas la configuration se situera
dans le dossier config avec comme principale différence le format utilisé.

 Laravel utilise des fichiers des PHP qui retourne des tableaux
 Symfony utilise par défaut des fichier yaml

Les routes
Maintenant que les framework sont installés on va pouvoir créer notre première
route pour créer une page. Dans le cas de Laravel on commence par créer le
controller

<?php
namespace App\Http\Controllers;

class HelloController extends Controller


{
public function hello()
{
return 'Hello';
}
}

Puis on déclare la route qui permet d'accéder à la méthode.

// routes/web.php
Route::get('/hello', [HelloController::class, 'hello'])->name('hello');

Côté Symfony il est possible de déclarer les routes au travers d'attribut dans le
controller directement.

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;

class BlogController extends AbstractController


{
#[Route('/hello', name: 'hello')]
public function hello(): Response
{
return new Response('hello');
}
}

Gérer la requête
Pour les 2 frameworks il est possible d'injecter un paramètre dans nos controllers
pour récupérer la requête.

public function hello(Request $request): Response


{
dd($request->query->get('name'));
}

On notera que l'objet Request présent dans Laravel étend de la class Request de
Symfony pour proposer des méthodes plus rapides pour effectuer des opérations de
bases.

Paramètre dans l'URL


En plus du traitement de la requête il est aussi possible de passer des paramètre
dans l'url. La syntaxe et le fonctionnement est similaire dans les 2 frameworks

# Laravel
Route::get('/hello/{name}', [HelloController::class, 'hello']);

# Symfony
#[Route('/hello/{name}')]

On pourra ensuite récupérer ce paramètre dans le controller sous forme de


paramètre.
public function hello (string $name) { }

Moteur de template
Pour rendre des pages HTML il sera possible d'utiliser un moteur de template et
c'est sur ce point qu'apparait une première différence entre les 2 frameworks.

Symfony utilise le moteur de template twig qui utilise sa propre syntaxe inspirée par
Django. Il est possible d'étendre le moteur en ajoutant des fonctions, filtres, et
balises

{% extends "base.html.twig" %}

{% block title %}Page Title{% endblock %}

{% block sidebar %}
{{ parent() }}
<p>This is appended to the master sidebar.</p>
{% endblock %}

{% block content %}
{% for post in posts %}
<article>
<h2>{{ post.title }}</h2>
<p>{{ post.excerpt }}</p>
<p><a href="{{ path('post.show', {slug: post.slug}) }}">Lire la suite</a></p>
</article>
{% endblock %}

Laravel utilise un moteur de template propre au framework : blade. Ce moteur étend


la syntaxe de PHP avec de nouvelles fonctionnalités mais accepte accepte aussi du
code PHP valide. Il peut être étendu à l'aide de nouvelles directives pour lesquelles il
faudra définir le code PHP à générer.

@extends('layouts.app')

@section('title', 'Page Title')

@section('sidebar')
@parent

<p>This is appended to the master sidebar.</p>


@endsection

@section('content')

@foreach($posts as $post)
<article>
<h2>{{ $post->title }}</h2>
<p>{{ $post->excerpt }}</p>
<p><a href="{{ route('post.show', ['slug' => $post->slug]) }}">Lire la suite</a></p>
</article>
@endforeach

@endsection

On notera que blade offre un système de composants qui permet d'inclure un


morceau de template en utilisant une syntaxe plus proche de l'HTML.

<form method="post">
<x-input :value="$post->title" label="Titre">
</form>

Formulaire
Une des tâche récurrente lorsque l'on fait du backend est la création et le traitement
de formulaire.

Symfony
Sur Symfony la création de formulaire passe par une classe dédiée qui va permettre
de représenter les données de notre formulaire. On notera la possibilité d'ajouter des
règle de validation sur les propriétés à l'aide d'attributs PHP.

<?php

namespace App\DTO;

use Symfony\Component\Validator\Constraints as Assert;

class ContactDTO
{

#[Assert\NotBlank()]
#[Assert\Length(min: 3)]
public string $name = '';

#[Assert\NotBlank()]
#[Assert\Email()]
public string $email = '';

#[Assert\NotBlank()]
#[Assert\Length(min: 10)]
public string $message = '';

Ensuite on peut créer la classe qui va représenter notre formulaire et ces champs.

<?php

namespace App\Form;
use App\DTO\ContactDTO;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class ContactForm extends AbstractType


{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name', TextType::class)
->add('email', TextType::class)
->add('message', TextareaType::class)
->add('save', SubmitType::class, ['label' => 'Nous contacter'])
;
}

public function configureOptions(OptionsResolver $resolver): void


{
$resolver->setDefaults([
'data_class' => ContactDTO::class,
]);
}
}

Ensuite, dans le controller il est possible de gérer le traitement du formulaire, et de


l'envoyer à Twig pour gérer l'affichage.

public function contact(Request $request): Response


{
$data = new ContactDTO();
$form = $this->createForm(ContactForm::class, $$data);
$form->handleRequest($request);

if ($form->isSubmitted() && $form->isValid()) {


// $data est muté avec les données du formulaire
// On peut aussi utiliser $form->getData() pour récupérer l'objet modifié
}

return $this->render('contact.html.twig', [
'form' => $form,
]);
}

Côté template le formulaire peut être généré à l'aide de la fonction form qui est
injecté dans Twig par Symfony.

{{ form(form) }}

Laravel
Sur Laravel il n'existe pas de classe pour représenter le formulaire, ni pour générer
le formulaire. Dans notre template blade on créera donc notre formulaire de manière
classique (on pourra utiliser des includes ou des composants pour simplifier l'écirute
des champs).

<form method="post">
@csrf
<div>
<label for="name">Name :</label>
<input type="text" name="name" id="name" value="{{ old('name') }}">
@error('name')
<div class="alert alert-danger">{{ $message }}</div>
@enderror
</div>
<div>
<label for="email">Email :</label>
<input type="email" id="email" name="email" id="email" value="{{ old('email') }}">
@error('email')
<div class="alert alert-danger">{{ $message }}</div>
@enderror
</div>
<div>
<label for="message">Name :</label>
<textarea type="text" id="message" value="">{{ old('message') }}</textarea>
@error('message')
<div class="alert alert-danger">{{ $message }}</div>
@enderror
</div>
<button type="submit">Nous contacter</button>
</form>

Lorsque le formulaire est soumis, et que des erreurs sont présentes, Laravel
redirigera automatiquement l'utilisateur vers le page précédente en sauvegardant les
données et les erreurs en session.

 La méthode old() permet de récupérer, depuis la session, la valeur de la


précédente soumission du formulaire.
 La directive @error permet de détecter si il y avait une erreur, et d'afficher
quelquechose si c'est le cas.

Maintenant pour la partie traitement, on va commencer par créer un objet requête


personnalisé qui permettra d'autoriser la requête et de valider son contenu.

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class ContactRequest extends FormRequest


{
public function authorize(): bool
{
return true;
}

public function rules(): array


{
return [
'name' => 'required|min:3',
'email' => 'required|email',
'message' => 'required|min:10',
];
}
}

Ensuite, on va créer une route pour la méthode POST et on utilisera notre objet
requête en paramètre de la méthode.

public function form() {


return view('contact/form');
}

public function store(ContactRequest $request) {


$data = $request->validated();
// $request->validated() contiendra les données validées sous forme de tableau.
}

API
Un autre cas d'utilisation de ces frameworks est la création d'une API.

Parser la requête
Lorsque l'on reçoit un appel il faut être capable de comprendre le contenu de la
requête et cela se fait très facilement pour les 2 frameworks. Côté Laravel on utilise
le même système de FromRequest.

public function store(ContactRequest $request) {


$data = $request->validated();
// $request->validated() contiendra les données validées sous forme de tableau.
}

Symfony permet lui aussi de traiter la requête facilement à travers un attribut au


niveau des controllers.

<?php
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;

public function contact(


#[MapRequestPayload]
ContactDTO $data
): Response
{
// $data contient les données du formulaire
}

Réponse d'API
Pour répondre correctement à une demande il est nécessaire de sérialiser les
données pour transformer un objet en réponse valide (JSON par exemple). Laravel
dispose d'un type de classe, dédié à la transformation des objets.

<?php

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource


{

public function toArray(Request $request): array


{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
}

Cette resource peut ensuite être utilisée pour renvoyer les données au niveau du
controller.

// Pour un seul élément on peut instancier et renvoyer la resource


public function user (User $user) {
return new UserResource($user);
}

// Pour plusieurs éléments on peut utiliser la méthode statique collection


public function users () {
$users = User::all();
return UserResource::collection($users);
}

Symfony utilise un système de serialisation pour transformer un objet et peut être


utilisé sur n'importe quel objet. Dans le cas des controllers une méthode json permet
de gérer la conversion d'une manière plus simple.

public function index(UserRepository $repository)


{
$users = $repository->findAll();
return $this->json($users, context: ['groups' => ['api:users']]);
}

Le paramètre "groups" permet de contrôler les propriétés que l'on souhaite exposer
au travers d'attributs.

L'ORM
L'ORM est aussi un gros point de différence entre les 2 frameworks.

Laravel utilise par défaut Eloquent qui est un ORM basé sur Active Record où le
Model est à la fois responsable de représenter une entité, mais aussi de gérer la
persistence des informations.

// Récupération
$post = Post::find(1);
// Modification
$post->name = "Marc";
$post->save();
// Création
$post2 = Post::create(['name' => 'Jean']);
// Suppression
$post3->destroy();

Symfony utilise par défaut Doctrine qui est un ORM basé sur le principe du Data
Mapper où on sépare la notion d'entité (objet représentant les données), de
Repository (objet servant à récupérer des entités) et de Manager (objet responsable
de la persistance)

$em = $this->getDoctrine()->getManager(); // L'entity manager, normalement récupéré en paramètre


du controller
// Récupération
$post = $em->getRepository(Post::class)->find(1);
// Modification
$post->setName('Marc');
// Création
$post2 = new Post();
$post2->setName('Jean');
$em->persist($post2);
// Suppression
$em->remove($post3);
// Dans tous les cas les données ne sont pas envoyées en base de données
// Pour cela il faut utiliser la méthode flush
$em->flush();

Eloquent a une syntaxe plus courte et une logique qui semble plus naturelle mais
cette apparente simplicité peut rapidement mener à des "fat models" car toute la
logique va être stocké au même endroit. Doctrine permet une meilleur séparation
mais s'avèrera relativement verbeux pour des cas simples.

Authentification
Pour l'authentification Laravel propose des "starter kits" qui permettent de mettre en
place toutes les opérations classique de gestion de compte utilisateur. Un de ces
starters kits est breeze qui va générer les controllers, models et template blade.

php artisan breeze:install

php artisan migrate


npm install
npm run dev

Le code sera généré dans le domaine de votre application et vous pouvez le


modifier pour ajouter le comportement que vous souhaitez en modifiant les sources.

Symfony, quant à lui, dispose d'un composant sécurité qui va permettre de gérer
l'authentification mais n'est pas configuré de base.

php bin/console make:user


php bin/console make:auth
php bin/cinsole make:registration-form

L'éxécution de ces commandes vous permettra de configurer la mise en place de


l'authentification. En revanche, ce qui est offert par défaut est beaucoup plus minimal
et il vous faudra développer la partie rappel de mot de passe, édition et suppression
de compte

Le même coeur : Le Service Container


Bien qu'ayant une approche différente au niveau des méthodes fournies, les 2
frameworks renferment le même système de Service container pour faire
communiquer les différents composants ensemble. Si par exemple on veut générer
une page :

// Sur laravel
view('posts/index'); // On fait appelle à une fonction globale

// Sur Symfony
$this->render('posts/index.html.twig') // On fait appelle à une méthode sur le controller

Bien que très différentes, ces 2 méthodes éxécutent un code relativement similaire si
on regarde ce qui se cache derrière :

// Sur Laravel
// view('posts/index');
Container::getInstance()->get('view')->make('posts/index');

// Sur Symfony
// $this->render('posts/index.html.twig')
$this->container->get('twig')->render('posts/index.html.twig')

Dans les 2 cas, le framework va commencer par créer un container qu'il va ensuite
remplir de différents services qui pourront ensuite être récupérés suivant les besoins
au sein de l'application. Laravel se différencie de Symfony par le fait qu'il rende le
container accessible n'importe où dans l'application gràce à l'utilisation d'un
Singleton, là ou Symfony imposera une plus grande rigueur en forçant l'utilisateur à
spécifier les dépendances via un fichier services.yml.

Donc Symfony ou Laravel ? les 2 !


Laravel se focalise sur la simplicité du code pour le développeur (arriver à la solution
simplement) ce qui passe par l'utilisation de méthode magique de PHP afin d'offrir
un code basé sur des conventions.

Symfony impose plus de rigueur et est plus proche d'un code PHP classique (à
l'exception de la configuration yaml) et est donc en général plus verbeux. Sa faible
utilisation de méthodes magique permet une meilleur navigation dans le code et une
analyse statique simplifiée.

Au final le choix va surtout dépendre de votre affinité vis à vis de la voix choisie par
ces 2 frameworks pour résoudre la problématique de la création d'application Web.

Vous aimerez peut-être aussi