PHP项目Symfony Controller抽象

wen PHP项目 2

本文目录导读:

PHP项目Symfony Controller抽象

  1. 基础抽象类方式
  2. 接口抽象方式
  3. Trait 组合方式
  4. 完整的实际项目示例
  5. 最佳实践建议

在 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);
    }
}

最佳实践建议

  1. 保持抽象层轻量:不要在抽象层添加过多逻辑,保持职责单一
  2. 使用依赖注入:通过构造函数注入通用依赖
  3. 提供便捷方法:如统一的响应格式、错误处理等
  4. 接口分离:为不同功能定义清晰的接口方法
  5. 参数验证:在抽象层提供参数验证和格式化方法
  6. 异常处理:统一异常捕获和响应格式

通过这种方式,可以大大提高代码复用性,保持控制器代码的整洁和一致性。

抱歉,评论功能暂时关闭!