2011-09-28 14 views
81

Trong cấu hình định tuyến của ứng dụng trên Symfony2, tôi có thể đề cập đến một tập tin như thế này:Truy cập tập tin tương đối sẽ kèm theo trong Symfony2

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

Có cách nào để truy cập vào một tập tin tương ứng với các gói trong một bộ điều khiển hoặc khác Mã PHP? Đặc biệt, tôi đang cố gắng sử dụng một đối tượng Symfony \ Component \ Yaml \ Parser để phân tích một tệp và tôi không muốn tham chiếu đến tệp đó hoàn toàn. 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 ra Symfony \ Component \ Finder \ Finder lớp, nhưng tôi không nghĩ rằng đó là những gì tôi đang tìm kiếm. Bất kỳ ý tưởng? Hoặc có lẽ tôi hoàn toàn nhìn ra một cách tốt hơn để làm điều này?

Trả lời

176

Như một vấn đề của thực tế, có một dịch vụ mà bạn có thể sử dụng cho điều này, các hạt nhân ($this->get('kernel')). Nó có một phương pháp 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') -> locateResource ("@ SomeBundle/Resources/config/config.yml"); // làm việc hoàn hảo –

+9

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

+2

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

6

Bạn có thể sử dụng $container->getParameter('kernel.root_dir') để nhận thư mục app của ứng dụng và duyệt các thư mục của mình vào tệp bạn muốn.

+0

Gói có thể nằm trong bất kỳ thư mục nào. Ví dụ thông thường: 'src/Acme/Gói/MyBundle',' src/Acme/MyBundle', 'nhà cung cấp/acme/my-bundle/src' và cứ tiếp tục như vậy. –

3

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

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

Bạn không được làm điều này, https://insight.sensiolabs.com/what-we-analyse/symfony.dependency_injection.use_dir_file_constant – ruudy

+0

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

+0

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

78
câu trả lời

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

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

$fileLocator sẽ là một thể hiện của \Symfony\Component\HttpKernel\Config\FileLocator. $path sẽ là đường dẫn đầy đủ, tuyệt đối đến tệp.

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

Để sử dụng nó với dependency injection:

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

Điểm tốt, 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 inject FileLocator thay vì Kernel :) – tomazahlin

+9

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

+0

Ofcourse, tôi đồng ý. – tomazahlin

Các vấn đề liên quan