You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ApiPlatform通用软删除控制器实现报错求助

问题:ApiPlatform通用软删除控制器参数解析失败

我使用ApiPlatform实现软删除逻辑:调用Delete请求时将实体的status设为0,而非直接删除数据库记录。目前能为每个实体单独编写自定义控制器,但希望实现一个通用控制器复用。我的实现思路:

  • 创建SoftDeletableInterface接口,强制实体拥有status属性及setStatus方法
  • 需要软删除的实体实现该接口
  • 在实体的ApiResource配置中指定通用SoftDeleteController处理Delete操作
  • 编写通用控制器代码

但运行时触发错误:无法解析__invoke方法的$entityClassName参数,提示可能未注册服务或未添加controller.service_arguments标签。当__invoke参数为具体实体类(如Channel)时可正常运行,尝试无类型声明的参数也报相同错误。


现有代码片段

SoftDeletableInterface接口

interface SoftDeletableInterface
{
    public function setStatus(int $status): static;
}

实体ApiResource配置

#[ApiResource(
    operations: [
        new Delete(
            controller: ChannelSoftDeleteController::class
        ),
    ]
)]

通用控制器代码

public function __invoke(string $entityClassName, $id): Response
{
    $entityClass = 'App\Entity\' . ucfirst($entityClassName);

    if (!class_exists($entityClass) || !is_subclass_of($entityClass, SoftDeletableInterface::class))    
    {
        return new Response(null, Response::HTTP_METHOD_NOT_ALLOWED);
    }

    $repository = $this->entityManager->getRepository($entityClass);
    $entity = $repository->find($id);

    if (!$entity) 
    {
        return new Response(null, Response::HTTP_NOT_FOUND);
    }

    $entity->setStatus(0);

    $this->entityManager->persist($entity);
    $this->entityManager->flush();

    return new Response(null, Response::HTTP_NO_CONTENT);
}

解决方案

1. 利用ApiPlatform内置参数获取实体类

ApiPlatform处理请求时会自动携带当前操作对应的实体类信息,无需手动传递$entityClassName。可以通过Operation对象直接获取实体类:

use Symfony\Component\HttpFoundation\Response;
use ApiPlatform\Metadata\Operation;
use Doctrine\ORM\EntityManagerInterface;

class SoftDeleteController
{
    public function __construct(private EntityManagerInterface $entityManager) {}

    public function __invoke($data, Operation $operation): Response
    {
        // 从Operation对象中获取当前实体类
        $entityClass = $operation->getClass();
        
        // 验证实体是否实现软删除接口
        if (!is_subclass_of($entityClass, SoftDeletableInterface::class)) {
            return new Response(null, Response::HTTP_METHOD_NOT_ALLOWED);
        }

        // 直接使用ApiPlatform自动注入的实体对象
        $data->setStatus(0);
        $this->entityManager->persist($data);
        $this->entityManager->flush();

        return new Response(null, Response::HTTP_NO_CONTENT);
    }
}

2. 统一配置实体的ApiResource

将所有需要软删除的实体的Delete操作控制器指定为通用SoftDeleteController:

#[ApiResource(
    operations: [
        new Delete(controller: SoftDeleteController::class),
        // 保留其他默认操作
        new Get(),
        new GetCollection(),
        new Post(),
        new Put()
    ]
)]
class Channel implements SoftDeletableInterface
{
    // 实体属性定义
    private int $status;

    // 实现接口方法
    public function setStatus(int $status): static
    {
        $this->status = $status;
        return $this;
    }
}

3. 确保控制器服务注册正确

Symfony默认会自动注册src/Controller目录下的控制器并添加controller.service_arguments标签。如果控制器在自定义目录,需在config/services.yaml中手动配置:

services:
    App\Controller\SoftDeleteController:
        autowire: true
        tags: ['controller.service_arguments']

4. 可选:添加Doctrine过滤器自动过滤软删除实体

为避免查询时返回已软删除的实体,可添加Doctrine全局过滤器:

// src/Filter/SoftDeleteFilter.php
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query\Filter\SQLFilter;

class SoftDeleteFilter extends SQLFilter
{
    public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias): string
    {
        if (!$targetEntity->reflClass->implementsInterface(SoftDeletableInterface::class)) {
            return '';
        }

        return "$targetTableAlias.status != 0";
    }
}

在config/packages/doctrine.yaml中启用过滤器:

doctrine:
    orm:
        filters:
            soft_delete:
                class: App\Filter\SoftDeleteFilter
                enabled: true

内容的提问来源于stack exchange,提问作者Stami

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 18:57:16