Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Repositories und Queries

Repositories und Queries

~15 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026

Mit der ersten Tabelle in der Datenbank verbinden wir jetzt endlich Controller UND echte Daten – über Doctrines Repository-Muster, das make:entity in Kapitel 19 bereits automatisch für uns angelegt hat.

Das generierte Repository

src/Repository/ProjectRepository.php
<?php

declare(strict_types=1);

namespace App\Repository;

use App\Entity\Project;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;

/**
 * @extends ServiceEntityRepository<Project>
 */
class ProjectRepository extends ServiceEntityRepository
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, Project::class);
    }
}

ServiceEntityRepository ist selbst ein Symfony SERVICE (Block 6 erklärt das Prinzip vertieft) – wir können es GENAU wie jeden anderen Service per Autowiring in einen Controller injizieren, KEINE manuelle Registrierung nötig.

Eingebaute Finder-Methoden

src/Controller/ProjectController.php
use App\Repository\ProjectRepository;

#[Route('/projects', name: 'project_index', methods: ['GET'])]
public function index(ProjectRepository $projectRepository): Response
{
    $projekte = $projectRepository->findAll();

    return $this->render('project/index.html.twig', [
        'projekte' => $projekte,
    ]);
}

#[Route('/projects/{id}', name: 'project_show', requirements: ['id' => '\d+'])]
public function show(int $id, ProjectRepository $projectRepository): Response
{
    $projekt = $projectRepository->find($id);

    if ($projekt === null) {
        throw $this->createNotFoundException('Projekt nicht gefunden.');
    }

    return $this->render('project/show.html.twig', [
        'projekt' => $projekt,
    ]);
}

find($id) sucht per Primärschlüssel, findAll() lädt ALLE Zeilen. createNotFoundException() (aus AbstractController) wirft eine NotFoundHttpException, die Symfony AUTOMATISCH in eine echte 404-Fehlerseite verwandelt.

findBy() und findOneBy()

// Alle Projekte, alphabetisch sortiert:
$projekte = $projectRepository->findBy([], ['name' => 'ASC']);

// Nur EIN Projekt nach exaktem Namen:
$projekt = $projectRepository->findOneBy(['name' => 'Website-Relaunch']);

Doctrine generiert diese Methoden "magisch" aus dem Feldnamen – es gibt auch die Kurzform findOneByName('Website-Relaunch'), allerdings ist die Array-Syntax oben EXPLIZITER und deshalb hier bevorzugt.

Ein Projekt speichern

use Doctrine\ORM\EntityManagerInterface;

#[Route('/projects/new', name: 'project_new', methods: ['GET', 'POST'])]
public function new(Request $request, EntityManagerInterface $entityManager): Response
{
    $form = $this->createForm(ProjectType::class, new Project());
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        $projekt = $form->getData();

        $entityManager->persist($projekt);
        $entityManager->flush();

        $this->addFlash('success', 'Projekt erfolgreich erstellt!');
        return $this->redirectToRoute('project_index');
    }

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

Zwei getrennte Schritte, IMMER in dieser Reihenfolge: persist() markiert die Entity als "soll gespeichert werden" (noch KEINE Datenbank-Aktion!), flush() schreibt ALLE seit dem letzten flush() markierten Änderungen TATSÄCHLICH in die Datenbank – in EINER Transaktion, selbst wenn mehrere Entities geändert wurden.

Achtung: Ein HÄUFIGER Anfängerfehler: persist() aufgerufen, aber flush() vergessen – die Entity landet dann NIE in der Datenbank, OHNE dass ein Fehler auftritt. Da createForm(ProjectType::class, new Project()) eine ECHTE Entity als zweites Argument bekommt (statt wie in Kapitel 15/16 eine *Data-Klasse), befüllt $form->getData() jetzt DIREKT diese Entity-Instanz.

Ein Projekt aktualisieren und löschen

// Aktualisieren: NICHTS Neues aufrufen, nur die Werte ändern - Doctrine erkennt Änderungen automatisch
$projekt->setName('Neuer Name');
$entityManager->flush(); // KEIN erneutes persist() nötig für bereits verwaltete Entities

// Löschen:
$entityManager->remove($projekt);
$entityManager->flush();

Tipp: Für BEREITS aus der Datenbank geladene (und damit von Doctrine "verwaltete") Entities reicht ein einfaches flush() zum Aktualisieren – Doctrine vergleicht automatisch den aktuellen Zustand mit dem beim Laden gespeicherten Ausgangszustand ("Unit of Work") und generiert NUR die tatsächlich nötigen UPDATE-Anweisungen.