文档
Symfony 入门教程:构建 Todo API
1. 背景
Symfony 是 PHP 企业级首选框架。本教程带你构建一个 Todo REST API,掌握控制器、ORM (Doctrine)、验证和序列化的核心用法。
2. 前置概念
| 概念 | 说明 |
|---|---|
| Entity | Doctrine ORM 映射到数据库表 |
| Repository | 实体查询类 |
| Validation | Symfony Validator 约束验证 |
| Serializer | 对象 ↔ JSON 序列化 |
| Maker Bundle | make: 命令快速生成代码 |
3. 分步操作
步骤一:创建项目
symfony new todo-api --webapp
cd todo-api
步骤二:创建 Todo 实体
php bin/console make:entity Todo
按提示输入字段:
title→string→255→ not nulldescription→text→ nullablecompleted→boolean→ defaultfalse
编辑 src/Entity/Todo.php 添加验证:
<?php
namespace App\Entity;
use App\Repository\TodoRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass: TodoRepository::class)]
class Todo
{
#[ORM\Id, ORM\GeneratedValue, ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 255)]
#[Assert\NotBlank, Assert\Length(min: 3, max: 255)]
private ?string $title = null;
#[ORM\Column(type: 'text', nullable: true)]
private ?string $description = null;
#[ORM\Column]
private bool $completed = false;
// getters & setters...
}
步骤三:迁移数据库
php bin/console make:migration
php bin/console doctrine:migrations:migrate
步骤四:创建控制器
php bin/console make:controller TodoController
<?php
namespace App\Controller;
use App\Entity\Todo;
use App\Repository\TodoRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Validator\Validator\ValidatorInterface;
#[Route('/api/todos')]
class TodoController extends AbstractController
{
#[Route('', methods: ['GET'])]
public function index(TodoRepository $repo): JsonResponse
{
return $this->json($repo->findAll());
}
#[Route('', methods: ['POST'])]
public function create(Request $request, EntityManagerInterface $em, ValidatorInterface $validator): JsonResponse
{
$data = json_decode($request->getContent(), true);
$todo = new Todo();
$todo->setTitle($data['title'] ?? '');
if (isset($data['description'])) $todo->setDescription($data['description']);
$errors = $validator->validate($todo);
if (count($errors) > 0) {
return $this->json(['errors' => (string) $errors], 422);
}
$em->persist($todo);
$em->flush();
return $this->json($todo, 201);
}
#[Route('/{id}', methods: ['GET'])]
public function show(Todo $todo): JsonResponse
{
return $this->json($todo);
}
#[Route('/{id}', methods: ['PUT'])]
public function update(Request $request, Todo $todo, EntityManagerInterface $em): JsonResponse
{
$data = json_decode($request->getContent(), true);
if (isset($data['title'])) $todo->setTitle($data['title']);
if (isset($data['description'])) $todo->setDescription($data['description']);
if (isset($data['completed'])) $todo->setCompleted($data['completed']);
$em->flush();
return $this->json($todo);
}
#[Route('/{id}', methods: ['DELETE'])]
public function delete(Todo $todo, EntityManagerInterface $em): JsonResponse
{
$em->remove($todo);
$em->flush();
return $this->json(null, 204);
}
}
4. 验证
curl -X POST http://localhost:8000/api/todos \
-H "Content-Type: application/json" \
-d '{"title":"学习 Symfony"}'
curl http://localhost:8000/api/todos
5. 思考题
- 如何用 DTO 解耦请求数据和实体?
- 如何使用 API Platform 代替手动编写 CRUD?
- 如何添加 JWT 认证保护 API?