Accéder aux fichiers relatifs au bundle dans Symfony2

83

Dans la configuration de routage d'une application Symfony2, je peux faire référence à un fichier comme celui-ci:

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

Existe-t-il un moyen d'accéder à un fichier relatif au bundle dans un contrôleur ou un autre code PHP? En particulier, j'essaie d'utiliser un objet Symfony \ Component \ Yaml \ Parser pour analyser un fichier, et je ne veux pas faire référence à ce fichier absolument. Essentiellement, je veux faire ceci:

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

J'ai vérifié la classe Symfony \ Component \ Finder \ Finder, mais je ne pense pas que ce soit ce que je recherche. Des idées? Ou peut-être que je néglige complètement une meilleure façon de faire cela?

Thomas Kelley
la source

Réponses:

179

En fait, il existe un service que vous pouvez utiliser pour cela, le kernel ( $this->get('kernel')). Il a une méthode appelée locateResource().

Par exemple:

$kernel = $container->getService('kernel');
$path = $kernel->locateResource('@AdmeDemoBundle/path/to/file/Foo.txt');
kgilden
la source
5
Exactement ce que je cherchais! $ this-> get ('kernel') -> LocateResource ("@ SomeBundle / Resources / config / config.yml"); // a parfaitement fonctionné
Thomas Kelley
9
@ tomtheman5: Assurez-vous d'attraper ses exceptions. Cette méthode lance \InvalidArgumentException, si le fichier est introuvable ou si le nom n'est pas valide, et \RuntimeExceptionsi le nom contient des caractères non valides / dangereux.
kgilden
2
J'adorerais vous donner plus que +1.
grippe
Comment (le cas échéant) utiliseriez-vous cette méthode à l'intérieur d'une entité doctrine, qui (je ne pense pas) aurait (ou devrait) avoir accès au noyau?
Michael.Lumley
1
@Morslamina Découvrez la réponse de Fazy.
Tek
78

La réponse de Thomas Kelley est bonne (et fonctionne!) Mais si vous utilisez l'injection de dépendances et / ou ne voulez pas lier votre code directement au noyau, il vaut mieux utiliser la classe / service FileLocator:

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

$fileLocatorsera une instance de \Symfony\Component\HttpKernel\Config\FileLocator. $pathsera le chemin absolu complet du fichier.

Même si le file_locator service lui-même utilise le noyau, c'est une dépendance beaucoup plus petite (plus facile à remplacer par votre propre implémentation, utiliser des doubles de test, etc.)

Pour l'utiliser avec l'injection de dépendances:

# 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
la source
Bon point, mais FileLocator obtient KernelInterface injecté, donc en gros, vous ne faites rien de mieux si vous injectez FileLocator au lieu de Kernel :)
tomazahlin
10
Je comprends votre point de vue et j'y ai pensé. Cependant, le problème n'est pas "de quel code est chargé / exécuté?", Mais "de quel code MyClassdépend-il?". L' FileLocatorimplémentation actuelle utilise KernelInterface, mais si cela change à l'avenir, il MyClassn'est pas nécessaire de le savoir. De plus, il est maintenant plus clair ce qui a MyClassvraiment besoin (et moins de tentation de le coupler avec d'autres fonctionnalités du noyau). Cela dit, le constructeur devrait probablement exiger Symfony\Component\Config\FileLocatorInterfaceplutôt que Symfony\Component\HttpKernel\Config\FileLocator. Ensuite, vous pouvez écrire le vôtre.
fazy
3
c'est la meilleure réponse
NDM
6

Vous pouvez utiliser $container->getParameter('kernel.root_dir')pour obtenir le appdossier de votre application et parcourir vos répertoires jusqu'au fichier souhaité.

Reuven
la source
Le bundle peut être dans n'importe quel répertoire. Exemples habituels: src/Acme/Bundle/MyBundle, src/Acme/MyBundle, vendor/acme/my-bundle/srcet ainsi de suite.
Marius Balčytis
3

Si vous souhaitez le faire dans un fichier situé dans, src/.../SomeBundle/...vous pouvez utiliser __DIR__pour obtenir le chemin complet du fichier actuel. Ensuite, ajoutez votre Resources/...chemin à cela comme

$foo = __DIR__.'/Resources/config/config.yml';
Prehfeldt
la source
@ruudy "Seuls les utilisateurs enregistrés avec un forfait payant peuvent obtenir un accès complet aux descriptions des règles. Cette page montre un exemple de ce que vous pouvez obtenir en vous abonnant."
prehfeldt
Je n'ai pas payé et je peux voir la description complète et l'explication de la façon de le résoudre. Il vous suffit peut-être de vous inscrire.
ruudy
Maintenant que je suis inscrit, je peux voir la page. Tout d'abord, il dit «ne devrait pas» et non «ne doit pas». Deuxièmement, à mon avis, cela n'est important que si vous prévoyez de publier votre code au public ou si vous prévoyez de remplacer le chemin de la ressource plus tard. Dans mes projets en source fermée, cela n'arrivera pas, donc ce n'est pas si important pour moi. Cela dépend du contexte dans lequel vous allez l'utiliser, si ce point est important pour vous. Néanmoins merci pour l'indice.
prehfeldt
Si vous suivez les recommandations, vous pouvez vous moquer du chemin ou jouer avec lui à des fins de test. Je ne suis pas natif anglais, il vaut mieux ne pas utiliser ces constantes php comme possible, encore moins sur un framework comme Symfony2.
ruudy