Truy cập tệp liên quan đến gói trong Symfony2


83

Trong cấu hình định tuyến của ứng dụng Symfony2, tôi có thể tham khảo một tệp như sau:

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

Có cách nào để truy cập tệp liên quan đến gói trong bộ điều khiển hoặc mã PHP khác không? Đặc biệt, tôi đang cố gắng sử dụng đối tượng Symfony \ Component \ Yaml \ Parser để phân tích cú pháp một tệp và tôi hoàn toàn không muốn đề cập đến tệp đó. Về cơ bản, tôi muốn làm điều này:

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

Tôi đã kiểm tra lớp Symfony \ Component \ Finder \ Finder, nhưng tôi không nghĩ đó là thứ mình đang tìm kiếm. Có ý kiến ​​gì không? Hoặc có thể tôi đang hoàn toàn bỏ qua một cách tốt hơn để làm điều này?

Câu trả lời:


179

Trên thực tế, có một dịch vụ bạn có thể sử dụng cho việc này, kernel ( $this->get('kernel')). Nó có một phương thức được gọi là locateResource().

Ví dụ:

$kernel = $container->getService('kernel');
$path = $kernel->locateResource('@AdmeDemoBundle/path/to/file/Foo.txt');

5
Chính xác những gì tôi đang tìm kiếm! $ this-> get ('kernel') -> seekResource ("@ SomeBundle / Resources / config / config.yml"); // làm việc một cách hoàn hảo
Thomas Kelley

9
@ tomtheman5: Hãy chắc chắn để nắm bắt các ngoại lệ của nó. Phương thức này sẽ ném \InvalidArgumentException, nếu không tìm thấy tệp hoặc tên không hợp lệ và \RuntimeExceptionnếu tên chứa các ký tự không hợp lệ / không an toàn.
kgilden

2
Rất muốn cung cấp cho bạn nhiều hơn chỉ +1.
cúm

Làm thế nào (nếu có) bạn sẽ sử dụng phương thức này bên trong một thực thể học thuyết, mà (tôi không nghĩ) sẽ (hoặc nên) có quyền truy cập vào hạt nhân?
Michael.Lumley

1
@Morslamina Hãy xem câu trả lời của fazy.
Tek

78

Câu trả lời của Thomas Kelley là tốt (và hoạt động!) Nhưng nếu bạn đang sử dụng phương pháp tiêm phụ thuộc và / hoặc không muốn liên kết trực tiếp mã của mình với hạt nhân, tốt hơn hết bạn nên sử dụng lớp / dịch vụ FileLocator:

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

$fileLocatorsẽ là một ví dụ của \Symfony\Component\HttpKernel\Config\FileLocator. $pathsẽ là đường dẫn đầy đủ, tuyệt đối đến tệp.

Mặc dù file_locator bản thân dịch vụ sử dụng hạt nhân, nó phụ thuộc nhỏ hơn nhiều (dễ dàng thay thế cho việc triển khai của chính bạn, sử dụng bộ đôi thử nghiệm, v.v.)

Để sử dụng nó với tiêm phụ thuộc:

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

Thoải mái điểm, nhưng FileLocator được KernelInterface tiêm, vì vậy về cơ bản, bạn không làm gì tốt hơn nếu bạn bơm FileLocator thay vì Kernel :)
tomazahlin

10
Tôi hiểu quan điểm của bạn, và tôi đã nghĩ đến điều đó. Tuy nhiên, vấn đề không phải là "mã nào được tải / thực thi?", Mà là "mã MyClassphụ thuộc vào cái gì?". Việc FileLocatortriển khai hiện tại sử dụng KernelInterface, nhưng nếu điều đó thay đổi trong tương lai MyClassthì không cần biết về nó. Ngoài ra, bây giờ nó rõ ràng hơn những gì MyClassthực sự cần (và ít bị cám dỗ hơn khi ghép nó với các tính năng nhân khác). Đã nói tất cả những điều đó, phương thức khởi tạo có lẽ nên yêu cầu Symfony\Component\Config\FileLocatorInterfacehơn là Symfony\Component\HttpKernel\Config\FileLocator. Sau đó, bạn có thể viết của riêng bạn.
fazy

3
đây là câu trả lời tốt hơn
NDM

6

Bạn có thể sử dụng $container->getParameter('kernel.root_dir')để lấy appthư mục của ứng dụng và duyệt các thư mục của bạn đến tệp bạn muốn.


Gói có thể nằm trong bất kỳ thư mục nào. Ví dụ thông thường: src/Acme/Bundle/MyBundle, src/Acme/MyBundle, vendor/acme/my-bundle/srcvà vân vân.
Marius Balčytis

3

Nếu bạn muốn làm điều đó trong một tệp nằm trong đó, src/.../SomeBundle/...bạn có thể sử dụng __DIR__để lấy đường dẫn đầy đủ của tệp hiện tại. Sau đó nối Resources/...đường dẫn của bạn vào như thế

$foo = __DIR__.'/Resources/config/config.yml';

@ruudy "Chỉ những người dùng đã đăng ký với gói trả phí mới có quyền truy cập đầy đủ vào các mô tả quy tắc. Trang này hiển thị một mẫu về những gì bạn có thể nhận được bằng cách đăng ký."
prehfeldt

tôi đã không trả tiền và tôi có thể xem mô tả đầy đủ và giải thích về cách giải quyết nó. Có lẽ bạn chỉ cần đăng ký.
ruudy

Bây giờ tôi đã đăng ký, tôi có thể xem trang. Trước hết nó nói "không nên" và không phải "không được". Thứ hai, điều này chỉ quan trọng nếu bạn định phát hành mã của mình ra công chúng hoặc định ghi đè đường dẫn tài nguyên sau này. Trong các dự án nguồn đóng của tôi, điều này sẽ không xảy ra, vì vậy điều này không quan trọng đối với tôi. Nó phụ thuộc vào ngữ cảnh mà bạn sẽ sử dụng nó, nếu điểm này là quan trọng đối với bạn. Tuy nhiên, cảm ơn vì gợi ý.
prehfeldt

Nếu bạn làm theo các khuyến nghị, bạn có thể mô phỏng đường dẫn hoặc chơi với nó với mục đích thử nghiệm. Tôi không phải là tiếng Anh bản địa, tốt hơn là không sử dụng hằng số php này là có thể tìm thấy được, ít hơn nhiều trên một khuôn khổ như Symfony2.
ruudy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.