使用 Doctrine 和 MySQL 在 Symfony 中构建动态 API
由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!
通过连接到真正的数据库,将您的 Symfony API 提升到一个新的水平。在本博客中,您将学习如何使用 Doctrine ORM 和 MySQL 来存储、检索和提供动态数据,使您的后端能够兼容 React、Vue、Angular 或任何现代前端框架。
使用 Doctrine 和 MySQL 在 Symfony 中构建动态 API
指数
- 介绍
- 步骤 1:在 Symfony 中设置数据库配置
- 步骤 2:安装 Doctrine ORM
- 步骤 3:创建实体
- 步骤 4:运行迁移
- 生成迁移文件
- 将迁移应用到数据库
- 确认表格已创建
- 步骤五:从数据库添加和检索产品
- 创建固定装置类
- 将赛程表加载到数据库中
- 更新 API 控制器以从数据库获取数据
- 步骤 6:在 React 中查看数据
- 统计数据
- 要点总结
- 有趣的事实
- 常见问题解答
- 结论
- 作者简介
- SEO设置
- 标签
介绍
当 API 提供的是真实、动态的数据而非固定、硬编码的响应时,其价值将大大提升。在本指南中,我们将扩展 Symfony API,使其能够连接 MySQL 数据库,从而实现数据的实时存储、检索和返回。我们将使用 Doctrine ORM 将数据库表映射到 PHP 实体,运行迁移来设置数据库模式,并将数据集成到 API 端点中。最终,您将拥有一个功能齐全、基于数据库的 API,可以随时为任何前端应用程序提供服务。
“移山者始于搬起小石。”——孔子
步骤 1:在 Symfony 中设置数据库配置
在存储和检索数据之前,Symfony 需要知道如何连接到您的数据库。这在项目根目录下的 .env 文件中进行配置。
在编辑器中打开 .env 文件,找到 DATABASE_URL 行。
DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8.0.32&charset=utf8mb4"
请将其替换为您的 MySQL 连接详细信息。例如:
DATABASE_URL="mysql://root:root@127.0.0.1:3306/symfony-app?serverVersion=8.0.32&charset=utf8mb4"
各部分说明:
root:root:数据库用户名和密码。127.0.0.1
:3306:MySQL 运行所在的主机和端口。symfony
:数据库名称。serverVersion
=8.0.32:您正在使用的 MySQL 版本。charset
=utf8mb4:字符编码,用于完全支持 Unicode(包括表情符号)。
提示:将敏感凭据存储在 .env.local 而不是 .env 中,这样它们就不会被提交到版本控制系统中。
步骤 2:安装 Doctrine ORM
Doctrine 是 Symfony 的默认 ORM(对象关系映射器)。它充当 PHP 对象(实体)和数据库表之间的桥梁。我们将使用它来创建表、存储数据,并在 API 中获取数据。
要安装 Doctrine ORM 及相关工具,请运行以下命令:
composer require symfony/orm-pack
composer require --dev doctrine/doctrine-fixtures-bundle
这些软件包的功能:
- symfony/orm-pack:安装 Doctrine ORM、数据库迁移和配置文件。
- doctrine/doctrine-fixtures-bundle:允许您加载用于测试的示例数据。(可选,但在开发过程中很有用)
安装完成后,Symfony 会创建一个默认的 config/packages/doctrine.yaml 文件,用于存储 Doctrine 的设置。它还会自动使用您在步骤 1 中设置的 DATABASE_URL。
要验证 Doctrine 是否已安装,请运行:
php bin/console doctrine:database:create
如果一切配置正确,您将看到一条消息,确认数据库已创建。
Created database `symfony-app` for connection named default
步骤 3:创建实体
在上一篇博客中,我们的 `/api/products` 接口返回的是硬编码的 JSON 数据。
现在,我们将通过将其连接到存储真实产品条目的数据库表,使其动态化。
为此,我们需要一个 `Product` 实体,Doctrine ORM 会将其映射到数据库表。
在 Symfony 中,实体代表一个数据库表,每个属性都映射到一列。我们将创建一个包含 `title`、`description` 和 `createdAt` 字段的 `Product` 实体。
在终端中运行以下命令:
php bin/console make:entity
出现提示时,请输入:
定义产品实体,包括标题、描述和创建时间字段。
Symfony 会生成 src/Entity/Product.php 文件。
它看起来会像这样:
<?php
namespace App\Entity;
use App\Repository\ProductRepository;
use Doctrine\DBAL\Types\Types;
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 $title = null;
#[ORM\Column(type: Types::TEXT)]
private ?string $description = null;
#[ORM\Column]
private ?\DateTimeImmutable $createdAt = null;
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): static
{
$this->title = $title;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(string $description): static
{
$this->description = $description;
return $this;
}
public function getCreatedAt(): ?\DateTimeImmutable
{
return $this->createdAt;
}
public function setCreatedAt(\DateTimeImmutable $createdAt): static
{
$this->createdAt = $createdAt;
return $this;
}
}
步骤 4:运行迁移
现在我们已经创建了 Product 实体,接下来我们将把它变成一个实际的数据库表,以便我们的 API 可以提供真实的数据记录。Symfony 使用 Doctrine 迁移将实体定义转换为数据库模式更改。运行迁移将在 MySQL 中创建 product 表,其中包含我们在步骤 3 中定义的字段。
生成迁移文件
php bin/console make:migration
使用 make:migration 成功生成迁移文件。
这会在 migrations/ 目录下创建一个新的迁移类。
打开它,你会看到 Doctrine 将要执行的 SQL 语句,例如,创建包含 id、title、description 和 created_at 列的产品表。
将迁移应用到数据库
php bin/console doctrine:migrations:migrate
系统会要求您确认。输入“yes”并按回车键。
使用 doctrine:migrations:migrate 成功应用了迁移。
验证表是否已创建。
登录 MySQL:
mysql -u root -p
然后:
USE symfony-app;
SHOW TABLES;
DESCRIBE product;
你应该能看到你的产品表,其中包含我们在产品实体中定义的列。
至此,我们的 Symfony 应用已准备好从数据库中存储和获取产品数据。下一步,我们将添加一些记录,以便我们的 API 可以返回这些记录,而不是占位符 JSON 数据。
“做得好胜过说得好。”——本杰明·富兰克林
步骤 5:从数据库添加和检索产品
我们将使用 Doctrine Fixtures 插入示例记录。Fixtures 是一种便捷的方式,可以将数据加载到数据库中以进行开发和测试。
使用 Composer 安装 orm-fixtures 包
composer require orm-fixtures --dev
要创建 Fixtures 类,
请运行:
php bin/console make:fixtures
当被问及时:
The class name of the fixtures to create (e.g. AppFixtures):
> ProductFixtures
Symfony 会创建src/DataFixtures/ProductFixtures.php 文件。
请按如下方式更新它:
<?php
namespace App\DataFixtures;
use App\Entity\Product;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
class ProductFixtures extends Fixture
{
public function load(ObjectManager $manager): void
{
$products = [
['title' => 'Sample Product', 'description' => 'This is a sample product description.'],
['title' => 'Another Product', 'description' => 'Another example description.'],
['title' => 'Third Product', 'description' => 'Yet another product for testing.'],
];
foreach ($products as $data) {
$product = new Product();
$product->setTitle($data['title']);
$product->setDescription($data['description']);
// createdAt will be set automatically by the constructor
$manager->persist($product);
}
$manager->flush();
}
}
我们希望每条记录都有一个创建时间戳,而无需在 fixtures 或表单中设置它。
因此,请更新 src/Entity/Product.php 构造函数。
public function __construct()
{
$this->createdAt = new \DateTimeImmutable();
}
将赛程表加载到数据库中
php bin/console doctrine:fixtures:load
系统会要求您确认。请输入“是”。Doctrine
会将示例记录插入产品表中。
更新 API 控制器,使其从数据库获取数据。
将 src/Controller/Api/ProductApiController.php 中的硬编码 JSON 替换为数据库查询:
<?php
namespace App\Controller\Api;
use App\Entity\Product;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;
class ProductApiController extends AbstractController
{
#[Route('/api/products', name: 'api_products', methods: ['GET'])]
public function index(EntityManagerInterface $em): JsonResponse
{
$products = $em->getRepository(Product::class)->findAll();
$data = [];
foreach ($products as $product) {
$data[] = [
'title' => $product->getTitle(),
'description' => $product->getDescription(),
];
}
return $this->json($data);
}
}
现在,当您访问http://localhost:8000/api/products时,您将看到来自数据库的数据,而不是硬编码的数组。
Symfony 产品 API 结果
步骤 6:在 React 中查看数据
现在,Symfony 不再返回固定数组,而是使用 Doctrine 直接从数据库中获取记录。
打开你的 React 应用,地址是:http://localhost:5173
React 前端现在显示从 Symfony API 获取的产品信息,数据存储在数据库中。
你会看到相同的产品列表界面,但这次内容是通过 Symfony 的 API 从数据库获取的。
“使用 Symfony 构建的 RESTful API 让您可以自由地为从简单的 React 应用到企业级平台等各种应用提供支持,所有应用都拥有简洁的后端。” - SensioLabs 工程团队
统计数据
- Symfony 的官方使用报告显示,全球有超过 60 万名开发者依靠 Symfony 和 Doctrine ORM 来构建强大的应用程序。
- 根据Doctrine 的 GitHub 代码库显示,该 ORM 已被下载超过 10 亿次,使其成为使用最广泛的 PHP 数据库抽象层之一。
要点总结
- Symfony 和 Doctrine 提供了一种简洁的方式来将 API 连接到数据库。
- 实体将 PHP 类映射到数据库表,使您的代码更具表现力和可维护性。
- Doctrine 迁移功能可以安全地处理模式更新,无需手动执行 SQL 语句。
- 夹具使预加载用于开发和测试的样本数据变得简单。
- 通过将硬编码的 JSON 替换为真正的数据库查询,您的 API 可以立即变得动态且可用于生产环境。
有趣的事实
- Doctrine ORM 被全球数千个 Symfony 项目使用,使其成为 PHP 生态系统中最经受过实战考验的 ORM 之一。
- Symfony 的数据库层不仅可以连接到 MySQL,还可以连接到 PostgreSQL、SQLite,甚至 Oracle。
- 借助 Doctrine 的查询构建器,您可以在 PHP 中编写富有表现力的查询,而无需在 SQL 和 PHP 代码之间切换。
常见问题解答
Q1:我可以在 Symfony 中使用 PostgreSQL 而不是 MySQL 吗?
A:可以。Doctrine 支持多种数据库引擎。您只需更新 .env 文件中的 DATABASE_URL 即可。
问2:生产环境需要使用 fixtures 吗?
答:不需要。fixtures 主要用于开发和测试。在生产环境中,通常通过应用程序或迁移来插入数据。
Q3:如果我之后更改了实体会怎样?
A:您可以运行 php bin/console make:migration,然后运行 php bin/console doctrine:migrations:migrate 来安全地更新数据库架构。
结论
从硬编码数据迁移到数据库驱动的 API 是后端开发中的一个重要里程碑。借助 Symfony、Doctrine 和 MySQL,这一过程简单直接,并为可扩展的应用程序奠定了坚实的基础。一旦您的 API 连接到真实数据,无论它是为 React 前端、移动应用还是其他客户端系统提供支持,您都将开启无限可能。这一步骤将您的 API 从演示版本转变为可供实际应用的成熟版本。
作者简介:Balasaranya Varadhalingam,AddWebSolution的软件工程师,专长于 PHP、Symfony 和 API 开发。
文章来源:https://dev.to/addwebsolutionpvtltd/building-a-dynamic-api-in-symfony-with-doctrine-and-mysql-5gg6





