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

基于工厂方法的PDF生成器架构疑问及ContainerInterface问题求助

问题描述

我在服务编排上遇到了问题,想要实现一个基于Provider的PDF生成器,预期流程是:带Provider参数的API请求 → GeneratorController::generate → 工厂方法 → 对应Generator类服务。目前想用Twig生成PDF,但碰到了ContainerInterface相关问题,不确定当前实现思路是否正确,想确认方向是否可行。


GeneratorController代码

public function generate($provider, Request $request): Response
{
    $generator = $this->factory->createGenerator($provider);
    $content = json_decode($request->getContent(), true);
    $generator->generate($content['params']);
    
    return new JsonResponse($generator->getData());
}

GeneratorFactory代码

class GeneratorFactory
{
    public function createGenerator($generator): Generator
    {
        $generatorName = "App\Generators\" . ucwords($generator) . "\Generator";

        if (!class_exists($generatorName)) {
            throw new \Exception("We dont find genarator with name: " . $generator);
        }

        return new $generatorName;
    }
}

工厂生成的Generator类代码

public function __construct()
{
    $this->object = new GeneratorObject;
    $this->validator = new Validator;
    $this->service = new PdfService();
}
public function generate(array $params): void
{
    $valided = $this->validator->Validate($params);
    if (!$valided) {
        throw new Exception("Invalid parameters", 1);
    }
    $this->setDataToObject($params);
    $pdf = $this->service->createPdf($this->object);
    $this->data = $pdf;
}

PDF服务类代码

public function createPdf(GeneratorObject $pdfObject): string
{
    $url = '';
    $html = $this->templating->render('pdf/index.html.twig',[$pdfObject]);

    return $url;
}

思路分析与优化建议

整体方向是对的

你采用的「工厂模式+Provider路由」思路符合服务编排的开闭原则,新增Provider类型时只需添加对应Generator类,无需修改工厂和控制器代码,扩展性良好。

核心问题:依赖硬编码导致ContainerInterface异常

你遇到的ContainerInterface问题,根源在于手动实例化依赖:

  1. Generator类构造函数里直接new PdfService(),但PdfService依赖的Twig服务(templating)是由Symfony容器管理的,手动实例化无法注入容器中的服务,必然会出现依赖缺失错误。
  2. 同理,Validator、GeneratorObject如果是需要容器注入的服务,手动实例化也会引发类似问题。

优化方案

  1. 让工厂依赖容器,实现依赖注入
    修改GeneratorFactory,注入容器后通过服务ID获取Generator实例,而非手动new:

    class GeneratorFactory
    {
        private $container;
    
        public function __construct(ContainerInterface $container)
        {
            $this->container = $container;
        }
    
        public function createGenerator($provider): Generator
        {
            $serviceId = "app.generator." . strtolower($provider);
            
            if (!$this->container->has($serviceId)) {
                throw new \Exception("Generator not found for provider: " . $provider);
            }
    
            return $this->container->get($serviceId);
        }
    }
    

    同时在services.yaml中注册所有Generator类:

    app.generator.invoice:
        class: App\Generators\Invoice\Generator
        arguments: ['@validator', '@App\Services\PdfService']
    
  2. Generator类通过构造函数注入依赖
    去掉手动实例化,改为依赖注入:

    private $object;
    private $validator;
    private $service;
    
    public function __construct(Validator $validator, PdfService $pdfService)
    {
        $this->object = new GeneratorObject; // 若GeneratorObject有依赖,同样注入
        $this->validator = $validator;
        $this->service = $pdfService;
    }
    
  3. PdfService注入Twig服务
    确保Twig环境通过构造函数注入:

    private $twig;
    
    public function __construct(Environment $twig)
    {
        $this->twig = $twig;
    }
    
    public function createPdf(GeneratorObject $pdfObject): string
    {
        $html = $this->twig->render('pdf/index.html.twig', ['data' => $pdfObject]);
        // 补充HTML转PDF逻辑(如使用wkhtmltopdf/TCPDF)
        $pdfUrl = $this->savePdfAndReturnUrl($html);
        return $pdfUrl;
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 08:34:56