Dostęp do plików związanych z paczką w Symfony2

83

W konfiguracji routingu aplikacji Symfony2 mogę odwołać się do takiego pliku:

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

Czy istnieje sposób na dostęp do pliku względem pakietu w kontrolerze lub innym kodzie PHP? W szczególności próbuję użyć obiektu Symfony \ Component \ Yaml \ Parser do parsowania pliku i nie chcę odwoływać się do tego pliku absolutnie. Zasadniczo chcę to zrobić:

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

Sprawdziłem klasę Symfony \ Component \ Finder \ Finder, ale nie sądzę, że tego właśnie szukam. Jakieś pomysły? A może kompletnie pomijam lepszy sposób na zrobienie tego?

Thomas Kelley
źródło

Odpowiedzi:

180

W rzeczywistości istnieje usługa, której możesz użyć do tego, kernel ( $this->get('kernel')). Ma metodę o nazwie locateResource().

Na przykład:

$kernel = $container->getService('kernel');
$path = $kernel->locateResource('@AdmeDemoBundle/path/to/file/Foo.txt');
kgilden
źródło
5
Dokładnie to, czego szukałem! $ this-> get ('kernel') -> locateResource ("@ SomeBundle / Resources / config / config.yml"); // działało idealnie
Thomas Kelley,
9
@ tomtheman5: Pamiętaj, aby złapać wyjątki. Ta metoda zgłasza \InvalidArgumentException, jeśli nie można znaleźć pliku lub nazwa jest nieprawidłowa i \RuntimeExceptionjeśli nazwa zawiera nieprawidłowe / niebezpieczne znaki.
kgilden
2
Chciałbym dać Ci więcej niż tylko +1.
grypa,
Jak (jeśli w ogóle) użyłbyś tej metody wewnątrz jednostki doktryny, która (nie sądzę) miałaby (lub powinna) mieć dostęp do jądra?
Michael.Lumley
1
@Morslamina Sprawdź odpowiedź faz.
Tek
78

Odpowiedź Thomasa Kelleya jest dobra (i działa!), Ale jeśli używasz iniekcji zależności i / lub nie chcesz wiązać swojego kodu bezpośrednio z jądrem, lepiej jest użyć klasy / usługi FileLocator:

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

$fileLocatorbędzie przykładem \Symfony\Component\HttpKernel\Config\FileLocator. $pathbędzie pełną, bezwzględną ścieżką do pliku.

Chociaż file_locatorsama usługa korzysta z jądra, jest to znacznie mniejsza zależność (łatwiej jest zastąpić własną implementację, użyć podwójnych testów testowych itp.)

Aby użyć go z iniekcją zależności:

# 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')
    }
}
fazy
źródło
Fajna uwaga, ale FileLocator dostaje wstrzyknięty KernelInterface, więc w zasadzie nic nie zrobisz lepiej, jeśli wstrzykniesz FileLocator zamiast Kernel :)
tomazahlin
10
Rozumiem twój punkt widzenia i pomyślałem o tym. Problemem nie jest jednak „jaki kod jest ładowany / wykonywany?”, Ale „od jakiego kodu MyClasszależy?”. Obecna FileLocatorimplementacja używa KernelInterface, ale jeśli to się zmieni w przyszłości MyClass, nie musisz o tym wiedzieć. Ponadto jest teraz jaśniejsze, czego MyClassnaprawdę potrzebuje (i mniej pokusy, aby połączyć to z innymi funkcjami jądra). Mimo wszystko konstruktor powinien Symfony\Component\Config\FileLocatorInterfaceraczej wymagać niż Symfony\Component\HttpKernel\Config\FileLocator. Następnie możesz napisać własne.
fazy
3
to jest lepsza odpowiedź
NDM
6

Możesz użyć, $container->getParameter('kernel.root_dir')aby uzyskać appfolder swojej aplikacji i przeglądać katalogi do żądanego pliku.

Reuven
źródło
Pakiet może znajdować się w dowolnym katalogu. Zwykłe przykłady: src/Acme/Bundle/MyBundle, src/Acme/MyBundle, vendor/acme/my-bundle/srci tak dalej.
Marius Balčytis
3

Jeśli chcesz to zrobić w pliku znajdującym się w src/.../SomeBundle/..., możesz użyć, __DIR__aby uzyskać pełną ścieżkę do bieżącego pliku. Następnie dołącz swoją Resources/...ścieżkę do tego podobnego

$foo = __DIR__.'/Resources/config/config.yml';
prehfeldt
źródło
@ruudy "Tylko zarejestrowani użytkownicy z płatnym abonamentem mogą uzyskać pełny dostęp do opisów reguł. Ta strona pokazuje próbkę tego, co możesz uzyskać, subskrybując."
prehfeldt
Nie zapłaciłem i widzę pełny opis i wyjaśnienie, jak go rozwiązać. Może wystarczy się zarejestrować.
ruudy
Teraz, gdy jestem zarejestrowany, widzę stronę. Przede wszystkim jest napisane „nie powinno” i nie „nie wolno”. Po drugie, imho jest to ważne tylko wtedy, gdy planujesz udostępnić swój kod publicznie lub planujesz później zastąpić ścieżkę zasobów. W moich projektach zamkniętych tak się nie stanie, więc nie jest to dla mnie takie ważne. To zależy od kontekstu, w którym zamierzasz go użyć, jeśli ten punkt jest dla Ciebie ważny. Niemniej jednak dzięki za podpowiedź.
prehfeldt
Jeśli zastosujesz się do zaleceń, możesz kpić ze ścieżki lub bawić się nią w celach testowych. Nie jestem anglojęzyczny, lepiej nie używać tych stałych php jako możliwych, a tym bardziej we frameworku takim jak Symfony2.
ruudy