【问题标题】:Symfony 5: error loading bundle at extension's load methodSymfony 5:在扩展的加载方法中加载包时出错
【发布时间】:2021-03-01 02:12:58
【问题描述】:

我正在尝试了解创建可重用捆绑包的必要步骤。我正在使用 Symfony 5.2 和 PHP 8.0。

我有两个同级目录,其中包含项目 MainProjectFirstModule

composer.json 用于项目MainProject

{
    "type": "project",
    "name": "modulartest/main_project",
    "license": "unlicense",
    "minimum-stability": "dev",
    "prefer-stable": true,
    "repositories": [{
        "type": "path",
        "url": "../FirstModule/"
    }],
    "require": {
        "php": ">=8.0",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "doctrine/annotations": "^1.12",
        "modulartest/first_module": "dev-master",
        "sensio/framework-extra-bundle": "^6.1",
        "symfony/console": "5.2.*",
        "symfony/dotenv": "5.2.*",
        "symfony/flex": "^1.3.1",
        "symfony/framework-bundle": "5.2.*",
        "symfony/maker-bundle": "^1.29",
        "symfony/yaml": "5.2.*"
    },
    "config": {
        "optimize-autoloader": true,
        "preferred-install": {
            "*": "dist"
        },
        "sort-packages": true
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "App\\Tests\\": "tests/"
        }
    },
    "replace": {
        "symfony/polyfill-ctype": "*",
        "symfony/polyfill-iconv": "*",
        "symfony/polyfill-php72": "*"
    },
    "scripts": {
        "auto-scripts": {
            "cache:clear": "symfony-cmd",
            "assets:install %PUBLIC_DIR%": "symfony-cmd"
        },
        "post-install-cmd": [
            "@auto-scripts"
        ],
        "post-update-cmd": [
            "@auto-scripts"
        ]
    },
    "conflict": {
        "symfony/symfony": "*"
    },
    "extra": {
        "symfony": {
            "allow-contrib": false,
            "require": "5.2.*"
        }
    }
}

composer.json 用于项目FirstModule

{
    "type": "symfony-bundle",
    "name": "modulartest/first_module",
    "license": "unlicense",
    "minimum-stability": "dev",
    "prefer-stable": true,
    "require": {
        "php": ">=8.0",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "sensio/framework-extra-bundle": "^6.1",
        "symfony/console": "5.2.*",
        "symfony/dotenv": "5.2.*",
        "symfony/flex": "^1.3.1",
        "symfony/framework-bundle": "5.2.*",
        "symfony/maker-bundle": "^1.29",
        "symfony/yaml": "5.2.*"
    },
    "config": {
        "optimize-autoloader": true,
        "preferred-install": {
            "*": "dist"
        },
        "sort-packages": true
    },
    "autoload": {
        "psr-4": {
            "ModularTest\\FirstModuleBundle\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "ModularTest\\FirstModuleBundle\\Tests\\": "tests/"
        }
    },
    "conflict": {
        "symfony/symfony": "*"
    },
    "extra": {
        "symfony": {
            "allow-contrib": false,
            "require": "5.2.*"
        }
    }
}

在 projeto FirstModule 中,我实现了一个服务和一个使用该服务的控制器,太简单了,只是为了测试。

FirstModule\src\Controller\FirstController.php中的服务代码:

<?php


namespace ModularTest\FirstModuleBundle\Service;


/**
 * Class FirstService
 * @package ModularTest\FirstModuleBundle\Service
 */
class FirstService
{
    /**
     * @return string
     */
    public function now(): string
    {
        return 'First Service time: '.date('c');
    }
}

FirstModule\src\Controller\FirstController.php 中的控制器代码:

<?php

namespace ModularTest\FirstModuleBundle\Controller;

use ModularTest\FirstModuleBundle\Service\FirstService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

/**
 * Class FirstController
 * @package ModularTest\FirstModuleBundle\Controller
 */
class FirstController extends AbstractController
{


    /**
     * FirstController constructor.
     * @param FirstService $firstService
     */
    public function __construct(private FirstService $firstService)
    {
    }

    /**
     * @return Response
     */
    #[Route('/first', name: 'modular_test_first_module_first')]
    public function index(): Response
    {
        return $this->json([
            'message' => 'Welcome to your new controller!',
            'path' => 'src/Controller/FirstController.php',
            'date' => $this->firstService->now()
        ]);
    }
}

我试图严格遵循 Symfony 文档在这三页中给出的说明:

因此,我以这种方式实现了 bundle 的类:

<?php


namespace ModularTest\FirstModuleBundle;


use Symfony\Component\HttpKernel\Bundle\Bundle;

/**
 * Class ModularTestFirstModuleBundle
 * @package ModularTest\FirstModuleBundle
 */
class ModularTestFirstModuleBundle extends Bundle
{
    /**
     * @return string
     */
    public function getPath(): string
    {
        return \dirname(__DIR__);
    }
}

我以这种方式实现了扩展的类:

<?php


namespace ModularTest\FirstModuleBundle\DependencyInjection;


use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;

/**
 * Class ModularTestFirstModuleExtension
 * @package ModularTest\FirstModuleBundle\DependencyInjection
 */
class ModularTestFirstModuleExtension extends Extension
{

    /**
     * @param array $configs
     * @param ContainerBuilder $container
     * @throws \Exception
     */
    public function load(array $configs, ContainerBuilder $container)
    {
        $loader = new YamlFileLoader(
            $container,
            new FileLocator(__DIR__.'/../Resources/config')
        );
        $loader->load('services.yaml');
    }
}

文件FirstModule\src\Resources\config\services.yaml里面的内容如下:

# This file is the entry point to configure your own services.
# Files in the packages/ subdirectory configure your dependencies.

# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:

services:
    # default configuration for services in *this* file
    _defaults:
        autowire: true      # Automatically injects dependencies in your services.
        autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.

    # makes classes in src/ available to be used as services
    # this creates a service per class whose id is the fully-qualified class name
    ModularTest\FirstModuleBundle\:
        resource: '../src/'
        exclude:
            - '../src/DependencyInjection/'
            - '../src/Entity/'
            - '../src/Kernel.php'
            - '../src/Tests/'

    # controllers are imported separately to make sure services can be injected
    # as action arguments even if you don't extend any base controller class
    ModularTest\FirstModuleBundle\Controller\:
        resource: '../src/Controller/'
        tags: ['controller.service_arguments']

    # add more service definitions when explicit configuration is needed
    # please note that last definitions always *replace* previous ones

好的,所有这些都完成了,我在MainProjectsymfony server:start 中运行了服务器,没有立即出现错误。然后我尝试浏览指向由bundle定义的控制器的路由,即https://127.0.0.1:8000/first,我收到了这个:

FileLocatorFileNotFoundException

文件“../src/”不存在(在:“C:\Users\eu\dev\php\symfony\modulartest\FirstModule\src\DependencyInjection/../Resources/config”)。

这是堆栈跟踪:

Symfony\Component\Config\Exception\FileLocatorFileNotFoundException:
The file "../src/" does not exist (in: "C:\Users\eu\dev\php\symfony\modulartest\FirstModule\src\DependencyInjection/../Resources/config").

  at C:\Users\eu\dev\php\symfony\modulartest\MainProject\vendor\symfony\config\FileLocator.php:71
  at Symfony\Component\Config\FileLocator->locate('../src/', 'C:\\Users\\eu\\dev\\php\\symfony\\modulartest\\FirstModule\\src\\DependencyInjection/../Resources/config', true)
     (C:\Users\eu\dev\php\symfony\modulartest\MainProject\vendor\symfony\config\Loader\FileLoader.php:117)
  at Symfony\Component\Config\Loader\FileLoader->glob('', true, array(object(FileExistenceResource)), false, false, array())
     (C:\Users\eu\dev\php\symfony\modulartest\MainProject\vendor\symfony\dependency-injection\Loader\FileLoader.php:176)
  at Symfony\Component\DependencyInjection\Loader\FileLoader->findClasses('ModularTest\\FirstModuleBundle\\', '../src/', array('../src/DependencyInjection/', '../src/Entity/', '../src/Kernel.php', '../src/Tests/'))
     (C:\Users\eu\dev\php\symfony\modulartest\MainProject\vendor\symfony\dependency-injection\Loader\FileLoader.php:99)
  at Symfony\Component\DependencyInjection\Loader\FileLoader->registerClasses(object(Definition), 'ModularTest\\FirstModuleBundle\\', '../src/', array('../src/DependencyInjection/', '../src/Entity/', '../src/Kernel.php', '../src/Tests/'))
     (C:\Users\eu\dev\php\symfony\modulartest\MainProject\vendor\symfony\dependency-injection\Loader\YamlFileLoader.php:671)
  at Symfony\Component\DependencyInjection\Loader\YamlFileLoader->parseDefinition('ModularTest\\FirstModuleBundle\\', array('resource' => '../src/', 'exclude' => array('../src/DependencyInjection/', '../src/Entity/', '../src/Kernel.php', '../src/Tests/')), 'C:\\Users\\eu\\dev\\php\\symfony\\modulartest\\FirstModule\\src\\DependencyInjection/../Resources/config\\services.yaml', array('autowire' => true, 'autoconfigure' => true))
     (C:\Users\eu\dev\php\symfony\modulartest\MainProject\vendor\symfony\dependency-injection\Loader\YamlFileLoader.php:234)
  at Symfony\Component\DependencyInjection\Loader\YamlFileLoader->parseDefinitions(array('parameters' => null, 'services' => array('ModularTest\FirstModuleBundle\' => array('resource' => '../src/', 'exclude' => array('../src/DependencyInjection/', '../src/Entity/', '../src/Kernel.php', '../src/Tests/')), 'ModularTest\FirstModuleBundle\Controller\' => array('resource' => '../src/Controller/', 'tags' => array('controller.service_arguments')))), 'C:\\Users\\eu\\dev\\php\\symfony\\modulartest\\FirstModule\\src\\DependencyInjection/../Resources/config\\services.yaml')
     (C:\Users\eu\dev\php\symfony\modulartest\MainProject\vendor\symfony\dependency-injection\Loader\YamlFileLoader.php:154)
  at Symfony\Component\DependencyInjection\Loader\YamlFileLoader->load('services.yaml')
     (C:\Users\eu\dev\php\symfony\modulartest\FirstModule\src\DependencyInjection\ModularTestFirstModuleExtension.php:30)
  at ModularTest\FirstModuleBundle\DependencyInjection\ModularTestFirstModuleExtension->load(array(array()), object(MergeExtensionConfigurationContainerBuilder))
     (C:\Users\eu\dev\php\symfony\modulartest\MainProject\vendor\symfony\dependency-injection\Compiler\MergeExtensionConfigurationPass.php:76)
  at Symfony\Component\DependencyInjection\Compiler\MergeExtensionConfigurationPass->process(object(ContainerBuilder))
     (C:\Users\eu\dev\php\symfony\modulartest\MainProject\vendor\symfony\http-kernel\DependencyInjection\MergeExtensionConfigurationPass.php:39)
  at Symfony\Component\HttpKernel\DependencyInjection\MergeExtensionConfigurationPass->process(object(ContainerBuilder))
     (C:\Users\eu\dev\php\symfony\modulartest\MainProject\vendor\symfony\dependency-injection\Compiler\Compiler.php:91)
  at Symfony\Component\DependencyInjection\Compiler\Compiler->compile(object(ContainerBuilder))
     (C:\Users\eu\dev\php\symfony\modulartest\MainProject\vendor\symfony\dependency-injection\ContainerBuilder.php:736)
  at Symfony\Component\DependencyInjection\ContainerBuilder->compile()
     (C:\Users\eu\dev\php\symfony\modulartest\MainProject\vendor\symfony\http-kernel\Kernel.php:541)
  at Symfony\Component\HttpKernel\Kernel->initializeContainer()
     (C:\Users\eu\dev\php\symfony\modulartest\MainProject\vendor\symfony\http-kernel\Kernel.php:780)
  at Symfony\Component\HttpKernel\Kernel->preBoot()
     (C:\Users\eu\dev\php\symfony\modulartest\MainProject\vendor\symfony\http-kernel\Kernel.php:183)
  at Symfony\Component\HttpKernel\Kernel->handle(object(Request))
     (C:\Users\eu\dev\php\symfony\modulartest\MainProject\public\index.php:20) 

接下来我可以尝试什么?

【问题讨论】:

    标签: php symfony symfony5


    【解决方案1】:

    你快到了。该错误消息具有误导性,因为它表明 src 是一个丢失的文件,当然它是一个目录。另外,它显然就在那里。该错误实际上来自 services.yaml 中的 autowire 部分。您从 config/services.yaml 复制了这些行,但没有考虑到包中 src 目录的相对路径不同的事实。

    # first_module/src/Resources/config/services.yaml
    services:
      _defaults:
        autowire: true
        autoconfigure: true
    
      ModularTest\FirstModuleBundle\:
        resource: '../../../src/' # Tweak the relative path
        exclude:
          - '../DependencyInjection/'
          - '../Entity/'
          - '../Kernel.php'
          - '../Tests/'
    
      ModularTest\FirstModuleBundle\Controller\:
        resource: '../../../src/Controller/'
        tags: ['controller.service_arguments']
    

    我发现从命令行解决这类接线问题更容易。我只是在主项目中创建了一个控制台命令并将 FirstService 注入其中。

    您不需要 Bundle::getPath()。调试时可能有那个。

    请注意,如果这些包真的要在多个应用程序之间共享,那么不鼓励使用自动装配。它可以工作,但您可能需要考虑像其他捆绑软件一样手动定义服务。

    顺便说一句,我忘记了在 composer.json 中使用存储库的路径属性。非常感谢你的帮忙。似乎比符号链接更好。

    【讨论】:

    • 谢谢!进行这些更改后,我收到一个新错误:===> 预计在文件“C:\Users\ACJP\dev\php\symfony\modulartest\FirstModule\ 中找到类“ModularTest\FirstModuleBundle\Resources\config\bundles” src\Resources\config\bundles.php" 从资源 "../../../src/" 导入服务时,但没有找到!检查资源使用的命名空间前缀。
    • 希望您已经发现需要将资源添加到排除的目录中,以防止 autowire 尝试从它碰巧找到的任何 .php 文件创建服务。
    • 我今天醒来时心情好多了。没有关于阅读文档或寻找答案的讲座。只需查看 config/routes/dev/web_profiler.yaml 即可了解如何从包中加载路由的示例。使用 bin/console debug:router 来测试你的工作。我强烈建议查看symfonycast tutorials
    • 请记住,您是从尝试进行相当高级的配置开始的。相对较少的 Symfony 开发人员在例行的基础上做的事情。早在 Symfony 2 首次发布时,使用 bundle 是很普遍的。但事实证明,这对新开发人员来说是一个很大的绊脚石,因此减少了对捆绑包的需求。与其从捆绑包开始,不如只构建一个应用程序,熟悉框架,然后在需要时进行重构。
    • 这样看。想象一下,如果有人对 python 有非常基本的了解而对 django 完全没有经验来找你,问如何根据一些相当粗略的规范设置企业应用程序。有一个 Symfony Reddit 板,这些模糊的问题可能有更好的机会。
    猜你喜欢
    • 2017-09-20
    • 1970-01-01
    • 1970-01-01
    • 2017-10-10
    • 1970-01-01
    • 2018-11-06
    • 2014-08-06
    • 1970-01-01
    相关资源
    最近更新 更多