Back to symfony.com

Lesson 8 of 12 · 4 min

Click any paragraph or press to highlight its code

Database & Doctrine

Symfony integrates Doctrine, the most powerful PHP ORM. Each database table maps to an entity: a plain PHP class where attributes describe the columns.

You don't even write these classes by hand: the interactive make:entity command generates and updates them, and the migration commands create the SQL to evolve your database schema safely.

To query the database, autowire the entity's repository. The built-in methods cover the common cases, and you add your own methods for complex queries.

When the built-in methods aren't enough, add your own using the QueryBuilder: a fluent API to compose queries in pure PHP. And for edge cases or special needs, you can always drop down to raw SQL.

<?phpnamespace App\Entity;use App\Repository\ArticleRepository;use Doctrine\ORM\Mapping as ORM;#[ORM\Entity(repositoryClass: ArticleRepository::class)]class Article{    #[ORM\Id]    #[ORM\GeneratedValue]    #[ORM\Column]    private ?int $id = null;    #[ORM\Column(length: 255)]    private ?string $title = null;    #[ORM\Column(type: 'text')]    private ?string $content = null;    // ... getters and setters}
<?phpnamespace App\Controller;use App\Repository\ArticleRepository;use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;use Symfony\Component\HttpFoundation\Response;use Symfony\Component\Routing\Attribute\Route;class ArticleController extends AbstractController{    #[Route('/articles')]    public function list(ArticleRepository $articles): Response    {        $latest = $articles->findBy([], ['title' => 'ASC'], limit: 10);        return $this->render('article/list.html.twig', [            'articles' => $latest,        ]);    }}
<?phpnamespace App\Repository;use App\Entity\Article;use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;use Doctrine\Persistence\ManagerRegistry;class ArticleRepository extends ServiceEntityRepository{    public function __construct(ManagerRegistry $registry)    {        parent::__construct($registry, Article::class);    }    public function findByKeyword(string $keyword): array    {        return $this->createQueryBuilder('article')            ->where('article.title LIKE :keyword')            ->setParameter('keyword', '%'.$keyword.'%')            ->getQuery()            ->getResult();    }}
$ php bin/console make:entity Article$ php bin/console make:migration$ php bin/console doctrine:migrations:migrate