本文目录导读:

在 Symfony 项目中,Controller 抽象是一个重要的概念,主要通过继承、接口和特性(Traits)来实现,以下是 Symfony Controller 抽象的核心实现方式:
基础抽象类方式
AbstractController(推荐方式)
<?php
// src/Controller/AbstractApiController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Serializer\SerializerInterface;
abstract class AbstractApiController extends AbstractController
{
protected SerializerInterface $serializer;
public function __construct(SerializerInterface $serializer)
{
$this->serializer = $serializer;
}
// 统一的 JSON 响应方法
protected function jsonResponse(mixed $data, int $status = 200, array $headers = []): JsonResponse
{
return $this->json($data, $status, $headers, [
'json_encode_options' => JSON_UNESCAPED_UNICODE
]);
}
// 统一的错误响应
protected function errorResponse(string $message, int $status = 400): JsonResponse
{
return $this->json([
'success' => false,
'error' => $message
], $status);
}
// 验证请求数据
protected function validateRequest(array $data, array $rules): array
{
$errors = [];
foreach ($rules as $field => $required) {
if ($required && !isset($data[$field])) {
$errors[$field] = "Field {$field} is required";
}
}
return $errors;
}
}
接口抽象方式
<?php
// src/Controller/ControllerInterface.php
namespace App\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
interface ControllerInterface
{
public function index(Request $request): Response;
public function show(int $id, Request $request): Response;
public function create(Request $request): Response;
public function update(int $id, Request $request): Response;
public function delete(int $id, Request $request): Response;
}
Trait 组合方式
<?php
// src/Traits/CrudOperationsTrait.php
namespace App\Traits;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
trait CrudOperationsTrait
{
protected function findAll(string $entityClass): JsonResponse
{
$entities = $this->getDoctrine()
->getRepository($entityClass)
->findAll();
return $this->json($entities);
}
protected function findById(string $entityClass, int $id): JsonResponse
{
$entity = $this->getDoctrine()
->getRepository($entityClass)
->find($id);
if (!$entity) {
return $this->json(['error' => 'Not found'], 404);
}
return $this->json($entity);
}
protected function createEntity(string $entityClass, array $data): JsonResponse
{
$entity = new $entityClass();
// 使用 Symfony Serializer 或手动设置属性
return $this->json($entity, 201);
}
}
// 使用 Trait 的 Controller
class ProductController extends AbstractController
{
use CrudOperationsTrait;
public function list(): JsonResponse
{
return $this->findAll(Product::class);
}
}
完整的实际项目示例
<?php
// src/Controller/BaseApiController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Doctrine\ORM\EntityManagerInterface;
abstract class BaseApiController extends AbstractController
{
public function __construct(
protected readonly EntityManagerInterface $entityManager,
protected readonly SerializerInterface $serializer,
protected readonly ValidatorInterface $validator
) {}
// 通用查询方法
protected function findOneOrFail(string $entityClass, int $id): object
{
$entity = $this->entityManager
->getRepository($entityClass)
->find($id);
if (!$entity) {
throw new NotFoundHttpException(
sprintf('Entity %s with id %d not found', $entityClass, $id)
);
}
return $entity;
}
// 通用分页查询
protected function paginateQuery(
string $entityClass,
int $page = 1,
int $limit = 10
): array {
$repository = $this->entityManager->getRepository($entityClass);
$paginator = $repository->createQueryBuilder('e')
->setFirstResult(($page - 1) * $limit)
->setMaxResults($limit)
->getQuery()
->getResult();
$total = $repository->createQueryBuilder('e')
->select('COUNT(e.id)')
->getQuery()
->getSingleScalarResult();
return [
'data' => $paginator,
'pagination' => [
'page' => $page,
'limit' => $limit,
'total' => $total,
'pages' => ceil($total / $limit)
]
];
}
// 通用实体保存
protected function saveEntity(object $entity, bool $flush = true): void
{
$errors = $this->validator->validate($entity);
if (count($errors) > 0) {
throw new ValidationException((string) $errors);
}
$this->entityManager->persist($entity);
if ($flush) {
$this->entityManager->flush();
}
}
// 统一成功响应
protected function successResponse(
mixed $data = null,
string $message = 'Success',
int $status = 200
): JsonResponse {
return $this->json([
'success' => true,
'message' => $message,
'data' => $data
], $status);
}
}
// 具体 Controller 实现
#[Route('/api/products')]
class ProductController extends BaseApiController
{
#[Route('', methods: ['GET'])]
public function index(Request $request): JsonResponse
{
$page = $request->query->getInt('page', 1);
$limit = $request->query->getInt('limit', 10);
$products = $this->paginateQuery(Product::class, $page, $limit);
return $this->successResponse($products);
}
#[Route('/{id}', methods: ['GET'])]
public function show(int $id): JsonResponse
{
$product = $this->findOneOrFail(Product::class, $id);
return $this->successResponse($product);
}
#[Route('', methods: ['POST'])]
public function create(Request $request): JsonResponse
{
$data = json_decode($request->getContent(), true);
$product = new Product();
$product->setName($data['name']);
$product->setPrice($data['price']);
$this->saveEntity($product);
return $this->successResponse($product, 'Product created', 201);
}
}
最佳实践建议
- 保持抽象层轻量:不要在抽象层添加过多逻辑,保持职责单一
- 使用依赖注入:通过构造函数注入通用依赖
- 提供便捷方法:如统一的响应格式、错误处理等
- 接口分离:为不同功能定义清晰的接口方法
- 参数验证:在抽象层提供参数验证和格式化方法
- 异常处理:统一异常捕获和响应格式
通过这种方式,可以大大提高代码复用性,保持控制器代码的整洁和一致性。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播