Zugriff auf Dateien in Bezug auf Bundle in Symfony2

83

In der Routing-Konfiguration einer Symfony2-App kann ich auf eine Datei wie die folgende verweisen:

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

Gibt es eine Möglichkeit, auf eine Datei relativ zum Bundle innerhalb eines Controllers oder eines anderen PHP-Codes zuzugreifen? Insbesondere versuche ich, ein Symfony \ Component \ Yaml \ Parser-Objekt zum Parsen einer Datei zu verwenden, und ich möchte nicht unbedingt auf diese Datei verweisen. Im Wesentlichen möchte ich dies tun:

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

Ich habe die Symfony \ Component \ Finder \ Finder-Klasse ausgecheckt, aber ich glaube nicht, dass ich danach suche. Irgendwelche Ideen? Oder übersehen ich vielleicht einen besseren Weg, dies zu tun?

Thomas Kelley
quelle

Antworten:

179

Tatsächlich gibt es einen Dienst, den Sie dafür verwenden können, den Kernel ( $this->get('kernel')). Es hat eine Methode namens locateResource().

Beispielsweise:

$kernel = $container->getService('kernel');
$path = $kernel->locateResource('@AdmeDemoBundle/path/to/file/Foo.txt');
kgilden
quelle
5
Genau das, wonach ich gesucht habe! $ this-> get ('kernel') -> LocateResource ("@ SomeBundle / Resources / config / config.yml"); // hat perfekt funktioniert
Thomas Kelley
9
@ tomtheman5: Achten Sie darauf, seine Ausnahmen zu fangen. Diese Methode wird ausgelöst \InvalidArgumentException, wenn die Datei nicht gefunden werden kann oder der Name ungültig ist und \RuntimeExceptionwenn der Name ungültige / unsichere Zeichen enthält.
kgilden
2
Würde Ihnen gerne mehr als nur +1 geben.
Grippe
Wie würden Sie (wenn überhaupt) diese Methode innerhalb einer Doktrinentität verwenden, die (glaube ich nicht) Zugriff auf den Kernel haben würde (oder sollte)?
Michael.Lumley
1
@ Morlamina Schauen Sie sich die Antwort von Fazy an.
Tek
78

Die Antwort von Thomas Kelley ist gut (und funktioniert!). Wenn Sie jedoch die Abhängigkeitsinjektion verwenden und / oder Ihren Code nicht direkt an den Kernel binden möchten, sollten Sie die FileLocator-Klasse / den FileLocator-Dienst verwenden:

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

$fileLocatorwird eine Instanz von sein \Symfony\Component\HttpKernel\Config\FileLocator. $pathwird der vollständige, absolute Pfad zur Datei sein.

Obwohl der file_locatorDienst selbst den Kernel verwendet, ist die Abhängigkeit viel geringer (einfacher, Ihre eigene Implementierung zu ersetzen, Testdoppel zu verwenden usw.)

So verwenden Sie es mit Abhängigkeitsinjektion:

# 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
quelle
Netter Punkt, aber FileLocator bekommt KernelInterface injiziert, also im Grunde tun Sie nichts besseres, wenn Sie FileLocator anstelle von Kernel injizieren :)
Tomazahlin
10
Ich verstehe Ihren Standpunkt und habe daran gedacht. Das Problem ist jedoch nicht "Welcher Code wird geladen / ausgeführt?", Sondern "Welcher Code hängt MyClassdavon ab?". Die aktuelle FileLocatorImplementierung verwendet KernelInterface, aber wenn sich dies in Zukunft MyClassändert, müssen Sie nichts darüber wissen. Außerdem ist jetzt klarer, was MyClasswirklich benötigt wird (und weniger Versuchung, es mit anderen Kernelfunktionen zu koppeln). Trotzdem sollte der Konstruktor wahrscheinlich Symfony\Component\Config\FileLocatorInterfaceeher verlangen als Symfony\Component\HttpKernel\Config\FileLocator. Dann können Sie Ihre eigenen schreiben.
Fazy
3
Dies ist die bessere Antwort
NDM
6

Sie können $container->getParameter('kernel.root_dir')den appOrdner Ihrer Anwendung abrufen und Ihre Verzeichnisse nach der gewünschten Datei durchsuchen.

Reuven
quelle
Das Bundle kann sich in einem beliebigen Verzeichnis befinden. Übliche Beispiele: src/Acme/Bundle/MyBundle, src/Acme/MyBundle, vendor/acme/my-bundle/srcund so weiter.
Marius Balčytis
3

Wenn Sie dies in einer Datei tun möchten, die sich in befindet src/.../SomeBundle/..., können Sie verwenden__DIR__ Sie den vollständigen Pfad der aktuellen Datei abrufen. Dann fügen Sie Ihren Resources/...Weg dazu gerne hinzu

$foo = __DIR__.'/Resources/config/config.yml';
prehfeldt
quelle
@ruudy "Nur registrierte Benutzer mit einem kostenpflichtigen Tarif können uneingeschränkt auf Regelbeschreibungen zugreifen. Diese Seite zeigt ein Beispiel dafür, was Sie durch Abonnieren erhalten können."
Prehfeldt
Ich habe nicht bezahlt und ich kann die vollständige Beschreibung und die Erklärung sehen, wie man es löst. Vielleicht müssen Sie sich nur registrieren.
Ruudy
Jetzt, wo ich registriert bin, kann ich die Seite sehen. Zunächst heißt es "sollte nicht" und nicht "darf nicht". Zweitens ist dies nur dann wichtig, wenn Sie planen, Ihren Code für die Öffentlichkeit freizugeben oder den Ressourcenpfad später zu überschreiben. In meinen Closed-Source-Projekten wird dies nicht passieren, daher ist dies für mich nicht so wichtig. Es hängt vom Kontext ab, in dem Sie es verwenden werden, ob dieser Punkt für Sie wichtig ist. Trotzdem danke für den Hinweis.
Prehfeldt
Wenn Sie den Empfehlungen folgen, können Sie den Pfad verspotten oder zu Testzwecken damit spielen. Ich bin kein englischer Muttersprachler, es ist besser, diese PHP-Konstanten nicht als möglich zu verwenden, geschweige denn auf einem Framework wie Symfony2.
Ruudy