Доступ к файлам относительно Bundle в Symfony2

83

В конфигурации маршрутизации приложения Symfony2 я могу ссылаться на такой файл:

somepage:
    prefix: someprefix
    resource: "@SomeBundle/Resources/config/config.yml"

Есть ли способ получить доступ к файлу относительно пакета внутри контроллера или другого кода PHP? В частности, я пытаюсь использовать объект Symfony \ Component \ Yaml \ Parser для анализа файла, и я не хочу полностью ссылаться на этот файл. По сути, я хочу это сделать:

$parser = new Parser();
$config = $parser->parse( file_get_contents("@SomeBundle/Resources/config/config.yml") );

Я проверил класс Symfony \ Component \ Finder \ Finder, но не думаю, что это то, что я ищу. Есть идеи? Или, может быть, я полностью упускаю из виду лучший способ сделать это?

Томас Келли
источник

Ответы:

180

На самом деле для этого можно использовать службу kernel ( $this->get('kernel')). У него есть метод под названием locateResource().

Например:

$kernel = $container->getService('kernel');
$path = $kernel->locateResource('@AdmeDemoBundle/path/to/file/Foo.txt');
кгилден
источник
5
Именно то, что я искал! $ this-> get ('kernel') -> locateResource ("@ SomeBundle / Resources / config / config.yml"); // сработало отлично
Томас Келли
9
@ tomtheman5: Обязательно поймите его исключения. Этот метод выдает ошибку \InvalidArgumentException, если файл не может быть найден или имя недействительно, а также \RuntimeExceptionесли имя содержит недопустимые / небезопасные символы.
kgilden
2
Хотел бы дать вам больше, чем просто +1.
грипп
Как (если вообще) вы бы использовали этот метод внутри объекта доктрины, который (я не думаю) будет (или должен) иметь доступ к ядру?
Майкл Ламли
1
@Morslamina Посмотрите ответ Фэзи.
Тек
78

Ответ Томаса Келли хорош (и работает!), Но если вы используете внедрение зависимостей и / или не хотите связывать свой код напрямую с ядром, вам лучше использовать класс / службу FileLocator:

$fileLocator = $container->get('file_locator');
$path = $fileLocator->locate('@MyBundle/path/to/file.txt')

$fileLocatorбудет экземпляром \Symfony\Component\HttpKernel\Config\FileLocator. $pathбудет полный, абсолютный путь к файлу.

Хотя сама file_locatorслужба использует ядро, это гораздо меньшая зависимость (проще заменить вашу собственную реализацию, использовать тестовые двойники и т. Д.)

Чтобы использовать его с внедрением зависимостей:

# services.yml

services:
    my_bundle.my_class:
        class: MyNamespace\MyClass
        arguments:
            - @file_locator

# MyClass.php

use Symfony\Component\Config\FileLocatorInterface as FileLocator;

class MyClass
{
    private $fileLocator;

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

    public function myMethod()
    {
        $path = $this->fileLocator->locate('@MyBundle/path/to/file.txt')
    }
}
нервный
источник
Хороший момент, но FileLocator вводит KernelInterface, так что, по сути, вы ничего не добьетесь большего, если вы введете FileLocator вместо Kernel :)
Томазалин
10
Я понимаю вашу точку зрения, и я подумал об этом. Однако проблема не в том, «какой код загружается / выполняется?», А в том, «от чего MyClassзависит код ?». Текущая FileLocatorреализация использует KernelInterface, но если это изменится в будущем MyClass, не нужно об этом знать. Кроме того, теперь стало яснее, что MyClassдействительно нужно (и меньше соблазна связать это с другими функциями ядра). Сказав все это, конструктор, вероятно, должен требовать, Symfony\Component\Config\FileLocatorInterfaceа не Symfony\Component\HttpKernel\Config\FileLocator. Тогда вы можете написать свой собственный.
fazy
3
это лучший ответ
NDM
6

Вы можете использовать его, $container->getParameter('kernel.root_dir')чтобы получить appпапку вашего приложения и найти в каталогах нужный файл.

Реувен
источник
Бандл может находиться в любом каталоге. Обычные примеры: src/Acme/Bundle/MyBundle, src/Acme/MyBundle, vendor/acme/my-bundle/srcи так далее.
Мариус Балчитис
3

Если вы хотите сделать это в файле, расположенном в, src/.../SomeBundle/...вы можете использовать __DIR__для получения полного пути к текущему файлу. Затем добавьте свой Resources/...путь к этому как

$foo = __DIR__.'/Resources/config/config.yml';
Prehfeldt
источник
@ruudy «Только зарегистрированные пользователи с платным планом могут получить полный доступ к описаниям правил. На этой странице показан пример того, что вы можете получить, подписавшись».
prehfeldt
Я не платил, и я могу увидеть полное описание и объяснение, как решить эту проблему. Возможно, вам нужно только зарегистрироваться.
ruudy
Теперь, когда я зарегистрирован, я вижу страницу. Во-первых, там написано «нельзя» и не «не должно». Во-вторых, imho, это важно только в том случае, если вы планируете опубликовать свой код для публики или планируете переопределить путь к ресурсу позже. В моих проектах с закрытым кодом этого не произойдет, поэтому для меня это не так важно. Это зависит от контекста, в котором вы собираетесь его использовать, важен ли этот момент для вас. Тем не менее спасибо за подсказку.
prehfeldt
Если вы будете следовать рекомендациям, вы можете поиздеваться над путем или поиграться с ним в целях тестирования. Я не родной английский, лучше не использовать эти php-константы по возможности, тем более на фреймворке, таком как Symfony2.
ruudy 07