Acceso a archivos relacionados con el paquete en Symfony2

83

En la configuración de enrutamiento de una aplicación Symfony2, puedo hacer referencia a un archivo como este:

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

¿Hay alguna forma de acceder a un archivo relativo al paquete dentro de un controlador u otro código PHP? En particular, estoy tratando de usar un objeto Symfony \ Component \ Yaml \ Parser para analizar un archivo, y no quiero referirme a ese archivo en absoluto. Esencialmente, quiero hacer esto:

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

Revisé la clase Symfony \ Component \ Finder \ Finder, pero no creo que eso sea lo que estoy buscando. ¿Algunas ideas? ¿O tal vez estoy pasando por alto por completo una mejor manera de hacer esto?

Thomas Kelley
fuente

Respuestas:

179

De hecho, hay un servicio que puede usar para esto, el kernel ( $this->get('kernel')). Tiene un método llamado locateResource().

Por ejemplo:

$kernel = $container->getService('kernel');
$path = $kernel->locateResource('@AdmeDemoBundle/path/to/file/Foo.txt');
kgilden
fuente
5
¡Exactamente lo que estaba buscando! $ this-> get ('kernel') -> LocateResource ("@ SomeBundle / Resources / config / config.yml"); // funcionó perfectamente
Thomas Kelley
9
@ tomtheman5: asegúrese de detectar sus excepciones. Este método arroja \InvalidArgumentException, si no se puede encontrar el archivo o el nombre no es válido, y \RuntimeExceptionsi el nombre contiene caracteres no válidos / inseguros.
kgilden
2
Me encantaría darte más que solo +1.
gripe
¿Cómo (en todo caso) usaría este método dentro de una entidad de doctrina, que (no creo) tendría (o debería) tener acceso al kernel?
Michael.Lumley
1
@Morslamina Mira la respuesta de Fazy.
Tek
78

La respuesta de Thomas Kelley es buena (¡y funciona!), Pero si está usando la inyección de dependencia y / o no desea vincular su código directamente al kernel, es mejor que use la clase / servicio FileLocator:

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

$fileLocatorserá una instancia de \Symfony\Component\HttpKernel\Config\FileLocator. $pathserá la ruta completa y absoluta al archivo.

Aunque el file_locatorservicio en sí usa el kernel, es una dependencia mucho más pequeña (más fácil de sustituir por su propia implementación, usar pruebas dobles, etc.)

Para usarlo con inyección de dependencia:

# 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
fuente
Buen punto, pero FileLocator se inyecta KernelInterface, así que básicamente, no hace nada mejor si inyecta FileLocator en lugar de Kernel :)
tomazahlin
10
Veo tu punto y pensé en eso. Sin embargo, el problema no es "¿qué código se carga / ejecuta?", Sino "¿de qué código MyClassdepende?". La FileLocatorimplementación actual usa KernelInterface, pero si eso cambia en el futuro MyClass, no necesita saberlo. Además, ahora está más claro lo que MyClassrealmente necesita (y menos tentación de combinarlo con otras características del kernel). Habiendo dicho todo eso, el constructor probablemente debería requerir en Symfony\Component\Config\FileLocatorInterfacelugar de Symfony\Component\HttpKernel\Config\FileLocator. Entonces puedes escribir el tuyo propio.
Fazy
3
esta es la mejor respuesta
NDM
6

Puede usar $container->getParameter('kernel.root_dir')para obtener la appcarpeta de su aplicación y buscar en sus directorios el archivo que desee.

Reuven
fuente
El paquete puede estar en cualquier directorio. Ejemplos habituales: src/Acme/Bundle/MyBundle, src/Acme/MyBundle, vendor/acme/my-bundle/srcy así sucesivamente.
Marius Balčytis
3

Si desea hacer eso en un archivo ubicado en src/.../SomeBundle/..., puede usar __DIR__para obtener la ruta completa del archivo actual. Luego agrega tu Resources/...camino a eso como

$foo = __DIR__.'/Resources/config/config.yml';
Prehfeldt
fuente
@ruudy "Solo los usuarios registrados con un plan pago pueden obtener acceso completo a las descripciones de las reglas. Esta página muestra una muestra de lo que puede obtener al suscribirse".
prehfeldt
No pagué y puedo ver la descripción completa y la explicación de cómo resolverlo. Quizás solo necesites registrarte.
ruudy
Ahora que estoy registrado puedo ver la página. En primer lugar, dice "no debería" y no "no debe". En segundo lugar, en mi humilde opinión, esto solo es importante si planea lanzar su código al público o planea anular la ruta de recursos más adelante. En mis proyectos de código cerrado esto no sucederá, así que esto no es tan importante para mí. Depende del contexto donde lo vayas a usar, si este punto es importante para ti. Sin embargo, gracias por la pista.
prehfeldt
Si sigue las recomendaciones, puede burlarse del camino o jugar con él con fines de prueba. No soy nativo de inglés, es mejor no usar estas constantes php como sea posible, mucho menos en un framework como Symfony2.
ruudy