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?

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');

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')
    }
}

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.


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';

@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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.