Symfony 4,从自定义类(非控制器类)中获取项目的根路径

45
在src/Utils目录中,我创建了一个名为Foo的自定义类,用于各种事情。我正在寻找一种方法来获取Symfony 4项目的绝对根路径。
从控制器中很容易实现:
$webPath = $this->get('kernel')->getProjectDir();
但是从我创建在src / Utils目录中的自定义类中,如何获取根路径目录?我可以将路径从控制器传递到Foo类中:
$webPath = $this->get('kernel')->getProjectDir();
$faa = new Foo($webPath);
$faa->doSomething();

但我认为更适合将这些信息存储在Foo类中,而在控制器类中只有“控制逻辑”。


将此值作为参数传递给Foo类__constructor__,该参数将被自动装配。 - u_mulder
1
嗯,能否给我提供一个构建方法的例子? - spacecodeur
5个回答

72

Symfony中AppKernel类在方法getProjectDir()下处理项目根目录。要在控制器中获取它,您可以执行以下操作:

在Symfony中,AppKernel类的getProjectDir()方法处理项目的根目录。要在控制器中获取它,您可以使用以下代码:

```php $projectDir = $this->getParameter('kernel.project_dir'); ```
$projectRoot = $this->get('kernel')->getProjectDir();

它将返回项目的根目录。

如果您需要在其中一个类中使用项目的根目录,您有两个选择,我将向您介绍这两种方法。第一种是将AppKernel作为依赖项传递:

class Foo 
{
    /** KernelInterface $appKernel */
    private $appKernel;

    public function __construct(KernelInterface $appKernel)
    {
        $this->appKernel = $appKernel;
    }
}

由于Symfony 4自动装配依赖项,它将自动注入到您的类中,您可以通过以下方式访问它:

感谢Symfony 4的自动装配依赖项功能,它将自动注入到您的类中,并且您可以通过以下方式访问它:

$this->appKernel->getProjectDir();

请注意: 我认为在没有真正需要和更多与AppKernel类相关的工作时,这不是一个好主意。特别是如果您想稍后为类创建单元测试。例如,您将自动通过需要创建AppKernel的模拟来增加复杂性。

第二个选项并且我认为更好的选择是仅传递一个目录路径字符串。您可以通过在config/services.yaml中定义一个服务来实现此目的,如下所示:

services:
    (...)
    MyNamespace\Foo:
        arguments:
            - %kernel.project_dir%

你的构造函数将如下所示:

class Foo 
{
    /** string $rootPath */
    private $rootPath;

    public function __construct(string $rootPath)
    {
        $this->rootPath = $rootPath;
    }
}

3
对于第一个解释,你还应该提到在类文件上面包含use Symfony\Component\HttpKernel\KernelInterface; - Kyeno
config/services.yaml and $rootPath are good idea instead of KernelInterface - Selim Reza

35

没有内核注入

config/services.yaml

services:
    _defaults:
        autowire: true
        autoconfigure: true
        bind:
            $projectDir: '%kernel.project_dir%'

....

class Foo
{
    private $projectDir;

    public function __construct(string $projectDir)
    {
        $this->projectDir = $projectDir;
    }
}

官方文档中的解决方案: https://symfony.com/blog/new-in-symfony-4-2-important-deprecations - Dte

27

如果您的类正在扩展:Symfony\Bundle\FrameworkBundle\Controller\AbstractController,那么可以通过以下方式获取根目录:

$projectRoot = $this->getParameter('kernel.project_dir');

或者

ContainerBagInterface注入到你的控制器中

protected $projectRoot;

public function __construct(ContainerBagInterface $containerBag)
{
    $this->projectRoot = $containerBag->get('kernel.project_dir');;
}

或者

更好的方法,也是推荐的方法

root_dir注入到您的Foo类中。在服务下的配置文件中添加以下内容。

services:
    foo:
        class:     App\Path\To\Foo
        arguments: ['%kernel.project_dir%']

容器应该在解析时将参数传递给您的类,Foo 类应该像这样:

<?php

namespace App\Path\To;

class Foo {

  private $projectDir;

  public function __construct($projectDir) 
  {
     $this->projectDir = $projectDir;
  }
}

在2019/2020/2021年,使用当前版本的Symfony(4,5+),这是实现此功能的方法。 - gview
1
最后一个例子对我来说非常有效。但是,我不得不将“%kernel.root_dir%”更改为“%kernel.project_dir%”。 - Nathanael

8
这是一份工作:
// from Foo class
use Symfony\Component\HttpKernel\KernelInterface;
...
class Foo{
    private $rootDir;
    public function __construct(KernelInterface $kernel)
    {
        $this->rootDir = $kernel->getProjectDir();
    }
    public function myfoomethod(){
        return $this->getRootDir();
    }
    public function getRootDir(){
        return $this->rootDir;
    }
}


// from the controller class 
use App\Utils\Foo;
...
class FaaController extends AbstractController
{
    /**
     * @Route("/scenario", name="scenario")
     */
    public function new(Foo $foo)
    {
        dump($foo->myfoomethod()); //show the dir path !
        return $this->render('faa/index.html.twig');
    }
}

但是 @Tomasz 的答案更好 ;) - spacecodeur
1
我很高兴你包含了使用语句。 - Benjamin
确实,没有其他解决方案提到 use Symfony\Component\HttpKernel\KernelInterface,但没有它什么都不起作用。 - pttsky

-2

最简单的方法是创建一个实用方法,而不注入无用的依赖项,就像这样(在我的情况下,它在src\Utils\Utils.php中):

namespace App\Utils;

public static function getRootDir(): string
{
    return __DIR__ . '/../..';
}

然后只需在任何地方调用它即可

Utils::getRootDir()

它可以在Windows和Linux上运行,但如果您喜欢,您可以使用DIRECTORY_SEPARATOR常量代替'/'


此外,使用__DIR__常量比Kernel::getProjectDir()方法更高效。后者需要实例化一个ReflectionObject,然后进行递归,直到找到包含composer.json的文件夹,并进行多个涉及I/O的检查,例如is_file()。使用__DIR__常量更好,因为它的值已经在内存中可用,无需访问物理磁盘。

1
这不是无用的依赖,而是可移植性。 - medunes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接