📋 Cheatsheet
Home Cheatsheet

📋 Symfony Cheatsheet

Klik een rij om het codevoorbeeld uit te klappen · Kopieer met de knop

🔍

⚡ Symfony CLI & Composer

composer create-project symfony/skeleton naam

Maakt een nieuw Symfony-project aan in een map met de opgegeven naam.

composer create-project symfony/skeleton mijn-app
cd mijn-app
php -S localhost:8000 -t public/
php bin/console cache:clear

Verwijdert de gecachete bestanden in var/cache/. Nodig na het aanpassen van routes of configuratie.

php bin/console cache:clear
# Of voor productieomgeving:
php bin/console cache:clear --env=prod
php bin/console make:controller NaamController

Genereert automatisch een controller-klasse en bijbehorend Twig-template.

php bin/console make:controller ProductController
# Maakt aan:
# src/Controller/ProductController.php
# templates/product/index.html.twig
php bin/console make:entity Naam

Start een interactieve wizard voor het aanmaken van een Entity met velden en types.

php bin/console make:entity Product
# Daarna: veldnaam, type (string/int/etc), lengte, nullable
# Maakt aan: src/Entity/Product.php + src/Repository/ProductRepository.php
php bin/console make:migration
php bin/console make:migration           # Migratie aanmaken
php bin/console doctrine:migrations:migrate  # Migratie uitvoeren
php bin/console doctrine:migrations:status  # Status bekijken
php bin/console debug:router
php bin/console debug:router            # Alle routes tonen
php bin/console debug:router app_home   # Specifieke route tonen
php bin/console debug:container        # Alle services tonen
composer require [pakket]
composer require twig              # Twig templates
composer require doctrine orm      # Database ORM
composer require form validator    # Formulieren
composer require security-bundle   # Authenticatie
composer require mailer            # E-mail verzenden
composer require webapp            # Alles voor een volledige app

🗺️ Routes

#[Route('/pad', name: 'naam')]
use Symfony\Component\Routing\Attribute\Route;

class HomeController extends AbstractController
{
    #[Route('/', name: 'app_home')]
    public function index(): Response
    {
        return $this->render('home/index.html.twig');
    }
}
#[Route('/product/{id}')]
#[Route('/product/{id}', name: 'product_show')]
public function show(int $id): Response
{
    // $id is automatisch beschikbaar als argument
    return $this->render('product/show.html.twig', ['id' => $id]);
}

// Meerdere parameters:
#[Route('/blog/{categorie}/{slug}', name: 'blog_show')]
public function blogShow(string $categorie, string $slug): Response { ... }
requirements: ['id' => '\d+']
// Alleen cijfers toegestaan voor {id}
#[Route('/product/{id}', name: 'product_show', requirements: ['id' => '\d+'])]

// Alleen letters voor {slug}
#[Route('/blog/{slug}', requirements: ['slug' => '[a-z0-9\-]+'])]
methods: ['GET', 'POST']
#[Route('/verwerk', name: 'verwerk', methods: ['POST'])]
public function verwerk(): Response { ... }

// Meerdere methoden:
#[Route('/item', name: 'item', methods: ['GET', 'POST'])]
$this->generateUrl('naam', ['id' => 5])
// In een controller:
$url = $this->generateUrl('product_show', ['id' => 5]);
// → "/product/5"

// In Twig:
// {{ path('product_show', {id: 5}) }}
// {{ url('product_show', {id: 5}) }}   ← absolute URL

🎮 Controllers

class … extends AbstractController
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

class ProductController extends AbstractController
{
    #[Route('/producten', name: 'product_index')]
    public function index(): Response
    {
        return $this->render('product/index.html.twig', [
            'title' => 'Alle producten',
        ]);
    }
}
return $this->render('template.html.twig', $data)
return $this->render('product/index.html.twig', [
    'producten' => $producten,   // beschikbaar als {{ producten }} in Twig
    'titel'     => 'Overzicht',
]);
return $this->redirectToRoute('naam')
// Eenvoudige redirect:
return $this->redirectToRoute('product_index');

// Met parameters:
return $this->redirectToRoute('product_show', ['id' => $product->getId()]);

// Externe URL redirect:
return $this->redirect('https://symfony.com');
return $this->json(['key' => 'value'])
return $this->json([
    'status' => 'ok',
    'data'   => $producten,  // arrays en objecten worden automatisch geserialiseerd
]);
// Geeft Content-Type: application/json terug
$request->get('naam')
use Symfony\Component\HttpFoundation\Request;

public function opslaan(Request $request): Response
{
    $naam   = $request->get('naam');                   // GET of POST
    $pagina = $request->query->get('pagina', 1);       // ?pagina=2
    $veld   = $request->request->get('veld');          // POST body
    $isPost = $request->isMethod('POST');              // boolean
}
throw $this->createNotFoundException()
$product = $repository->find($id);

if (!$product) {
    throw $this->createNotFoundException('Product niet gevonden');
}
// Symfony toont automatisch de 404-pagina

🌿 Twig Templates

{{ variabele }}
{{ naam }}              {# Eenvoudige variabele #}
{{ product.naam }}     {# Property van een object #}
{{ producten[0] }}     {# Eerste element van array #}
{{ naam|upper }}       {# Filter: HOOFDLETTERS #}
{{ naam|lower }}       {# filter: kleine letters #}
{{ naam|length }}      {# Aantal tekens #}
{{ prijs|number_format(2, ',', '.') }}  {# 1.234,56 #}
{{ datum|date('d-m-Y') }}
{{ datum|date('d-m-Y') }}         {# 18-05-2026 #}
{{ datum|date('d F Y') }}         {# 18 May 2026 #}
{{ datum|date('H:i') }}           {# 14:30 #}
{{ 'now'|date('Y') }}             {# Huidig jaar #}
{% if conditie %}…{% endif %}
{% if leeftijd >= 18 %}
  Volwassen
{% elseif leeftijd >= 12 %}
  Tiener
{% else %}
  Kind
{% endif %}

{% if producten is empty %}
  Geen producten gevonden.
{% endif %}

{% if gebruiker is defined and gebruiker %}
  Welkom, {{ gebruiker.naam }}!
{% endif %}
{% for item in items %}…{% endfor %}
{% for product in producten %}
  
  • {{ loop.index }}. {{ product.naam }}
  • {% else %}

    Geen producten gevonden.

    {% endfor %} {# Loop variabelen: #} {# loop.index → 1, 2, 3, … #} {# loop.index0 → 0, 1, 2, … #} {# loop.first → true bij eerste item #} {# loop.last → true bij laatste item #} {# loop.length → totaal aantal items #}
    {% extends 'base.html.twig' %}
    {# base.html.twig #}
    <!DOCTYPE html>
    <html>
    <body>
      {% block content %}{% endblock %}
      {% block javascripts %}{% endblock %}
    </body>
    </html>
    
    {# product/index.html.twig #}
    {% extends 'base.html.twig' %}
    
    {% block content %}
      <h1>Producten</h1>
    {% endblock %}
    {% include %} · {% set %} · path()
    {% include 'partials/_nav.html.twig' %}
    {% include 'card.html.twig' with {product: item} %}
    
    {% set totaal = prijs * aantal %}
    {% set bericht = 'Hallo ' ~ naam %}
    
    {{ path('product_show', {id: product.id}) }}
    {{ asset('css/style.css') }}

    🗄️ Doctrine ORM

    #[ORM\Entity] · #[ORM\Column]
    use Doctrine\ORM\Mapping as ORM;
    
    #[ORM\Entity(repositoryClass: ProductRepository::class)]
    class Product
    {
        #[ORM\Id]
        #[ORM\GeneratedValue]
        #[ORM\Column]
        private ?int $id = null;
    
        #[ORM\Column(length: 255)]
        private ?string $naam = null;
    
        #[ORM\Column(type: 'float')]
        private ?float $prijs = null;
    
        #[ORM\Column(type: 'boolean')]
        private bool $actief = true;
    
        // Getters en setters...
    }
    $em->persist($obj); $em->flush();
    use Doctrine\ORM\EntityManagerInterface;
    
    class ProductController extends AbstractController
    {
        public function __construct(
            private EntityManagerInterface $em
        ) {}
    
        public function nieuw(): Response
        {
            $product = new Product();
            $product->setNaam('Laptop');
            $product->setPrijs(999.95);
    
            $this->em->persist($product); // registreren
            $this->em->flush();           // SQL INSERT uitvoeren
    
            return $this->redirectToRoute('product_index');
        }
    
        public function update(Product $product): Response
        {
            $product->setPrijs(899.00); // alleen wijzigen
            $this->em->flush();         // SQL UPDATE uitvoeren
            // Geen persist() nodig voor bestaand object!
        }
    }
    findAll() · find($id) · findBy([])
    $repo = $this->em->getRepository(Product::class);
    
    $all    = $repo->findAll();                              // alle rijen
    $one    = $repo->find(5);                                // op id
    $active = $repo->findBy(['actief' => true]);             // gefilterd
    $sorted = $repo->findBy(['actief' => true], ['naam' => 'ASC']); // gesorteerd
    $eerste = $repo->findOneBy(['naam' => 'Laptop']);        // één resultaat
    
    // Via autowiring (aanbevolen):
    class ProductController extends AbstractController
    {
        public function __construct(
            private ProductRepository $repo
        ) {}
    }
    createQueryBuilder('p')->where(…)
    // In een Repository-methode:
    public function findGoedkoop(float $max): array
    {
        return $this->createQueryBuilder('p')
            ->andWhere('p.prijs < :max')
            ->setParameter('max', $max)
            ->orderBy('p.prijs', 'ASC')
            ->setMaxResults(10)
            ->getQuery()
            ->getResult();
    }
    #[ORM\ManyToOne] · #[ORM\OneToMany]
    // Product behoort tot één Category (many products → one category)
    #[ORM\ManyToOne(targetEntity: Category::class)]
    #[ORM\JoinColumn(nullable: false)]
    private ?Category $category = null;
    
    // Category heeft meerdere Products (one category → many products)
    #[ORM\OneToMany(mappedBy: 'category', targetEntity: Product::class)]
    private Collection $products;
    
    // In Twig:
    // {{ product.category.naam }}
    // {% for p in category.products %}{{ p.naam }}{% endfor %}

    📝 Formulieren

    class NaamType extends AbstractType
    namespace App\Form;
    
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\Extension\Core\Type\EmailType;
    use Symfony\Component\Form\Extension\Core\Type\SubmitType;
    use Symfony\Component\Form\Extension\Core\Type\TextType;
    use Symfony\Component\Form\FormBuilderInterface;
    
    class ProductType extends AbstractType
    {
        public function buildForm(FormBuilderInterface $builder, array $options): void
        {
            $builder
                ->add('naam',  TextType::class,  ['label' => 'Productnaam'])
                ->add('email', EmailType::class, ['label' => 'E-mail'])
                ->add('opslaan', SubmitType::class, ['label' => 'Opslaan']);
        }
    }
    handleRequest · isSubmitted · isValid
    public function nieuw(Request $request): Response
    {
        $product = new Product();
        $form = $this->createForm(ProductType::class, $product);
    
        $form->handleRequest($request);
    
        if ($form->isSubmitted() && $form->isValid()) {
            // $product is nu gevuld met formulierdata
            $this->em->persist($product);
            $this->em->flush();
            $this->addFlash('success', 'Opgeslagen!');
            return $this->redirectToRoute('product_index');
        }
    
        return $this->render('product/nieuw.html.twig', [
            'form' => $form,
        ]);
    }
    #[Assert\NotBlank] · #[Assert\Email]
    use Symfony\Component\Validator\Constraints as Assert;
    
    class Product
    {
        #[Assert\NotBlank(message: 'Vul een naam in')]
        #[Assert\Length(min: 2, max: 100)]
        private ?string $naam = null;
    
        #[Assert\Email]
        #[Assert\NotBlank]
        private ?string $email = null;
    
        #[Assert\Range(min: 0, max: 99999)]
        #[Assert\NotNull]
        private ?float $prijs = null;
    
        #[Assert\Regex(pattern: '/^[a-z0-9]+$/', message: 'Alleen kleine letters en cijfers')]
        private ?string $slug = null;
    }
    form_start · form_row · form_end
    {{ form_start(form) }}
      {{ form_row(form.naam) }}    {# label + input + fout #}
      {{ form_row(form.email) }}
      {{ form_row(form.opslaan) }}
    {{ form_end(form) }}           {# sluit form + CSRF token #}
    
    {# Of alles in één: #}
    {{ form(form) }}
    
    {# Foutmeldingen tonen: #}
    {{ form_errors(form) }}
    {{ form_errors(form.naam) }}   {# veld-specifiek #}
    $this->addFlash('success', '…')
    // In controller (na redirect):
    $this->addFlash('success', 'Product opgeslagen!');
    $this->addFlash('error',   'Er ging iets mis.');
    return $this->redirectToRoute('product_index');
    {# In Twig (base.html.twig): #}
    {% for type, messages in app.flashes %}
      {% for message in messages %}
        <div class="flash flash-{{ type }}">{{ message }}</div>
      {% endfor %}
    {% endfor %}

    SymfonyLearn · Cheatsheet · Officiële documentatie →