2012-01-03 23 views
12

Có 2 câu hỏi ở đây nói rằng việc tiêm toàn bộ vùng chứa dịch vụ sẽ giải quyết vấn đề này. Nhưng câu hỏi ... xem dưới đây (sự khác biệt giữa lưu ý thử 2 & 3) ...Tham khảo Thông tư khi tiêm Ngữ cảnh Bảo mật vào (Trình lắng nghe Thực thể) Lớp

Hãy thử 1

public function __construct(SecurityContext $securityContext) { 
    $this->securityContext = $securityContext); 
} 

Curcular tham khảo. Okay ...

Hãy thử 2

public function __construct(ContainerInterface $container) { 
    $this->securityContext = $container->get('security.context'); 
} 

Thông tư tham khảo (Tại sao?, tôi tiêm container như trong thử 3 ngoại trừ tôi đã bối cảnh an ninh duy nhất)

Thử 3

public function __construct(ContainerInterface $container) { 
    $this->container = $container; 
} 

Hoạt động.

+0

hãy đăng toàn bộ mã ví dụ. Thông tư Ref thường có nghĩa là bạn đang cố gắng tiêm một dịch vụ đã được tiêm một số cách khác vào cùng một lớp. (Vấn đề phổ biến nhất là người quản lý thực thể trong thính giả học thuyết) – Inoryy

Trả lời

25

Điều này xảy ra vì ngữ cảnh bảo mật của bạn phụ thuộc vào người nghe này, có thể thông qua trình quản lý đối tượng được đưa vào nhà cung cấp người dùng. Giải pháp tốt nhất là đưa container vào trình nghe và truy cập vào ngữ cảnh bảo mật một cách uể oải.

Tôi thường không thích tiêm toàn bộ vùng chứa vào một dịch vụ, nhưng tạo ngoại lệ với trình nghe Doctrine vì chúng được tải háo hức và do đó nên lười nhất có thể.

+0

Hmm, có ý nghĩa gì đó, nhưng tôi không hiểu cách "Thử 2" sẽ thất bại khi 3 thành công. Vâng, "lười" của nó nhưng liệu một biến thể hiện có làm rối loạn hoạt động của một lớp khác không? Hmm ... –

+0

Thùng chứa theo dõi những dịch vụ mà nó đang trong quá trình tạo. Nếu 'get()' được gọi cho một trong các dịch vụ này, nó đã có trong quá trình tạo, một ngoại lệ tham chiếu vòng tròn được ném ra. Đó là lý do tại sao bạn đang nhận được ngoại lệ này khi bạn gọi cho bối cảnh an ninh từ bên trong constructor, nhưng không phải khác. Khi hàm tạo được gọi là vùng chứa đã làm việc để tạo ngữ cảnh bảo mật. –

+1

Tiêm thùng chứa không bao giờ là «giải pháp tốt nhất». Tôi nghĩ cách tiếp cận tốt hơn sẽ là sử dụng «Dịch vụ Lười biếng». –

1

Lý do "2" không thành công và "3" không phải vì trong tùy chọn 2 bạn đang cố gắng truy cập ngữ cảnh bảo mật ngay lập tức từ vùng chứa khi có thể chưa được điền.

Tốt nhất tôi có thể nói, Symfony2 phân tích cú pháp thông qua cấu hình và khởi tạo dịch vụ sau lần khác và sau đó chuyển sang xử lý phần còn lại của yêu cầu.

Điều này có nghĩa là bạn không nhất thiết phải truy cập vào các phần khác nhau của vùng chứa vì nó có thể đang tải chúng theo thứ tự khác. Vì vậy, bạn có con trỏ bộ nhớ để chứa, và lưu trữ đó, nhưng sau đó để cho khuôn khổ kết thúc xây dựng các thùng chứa đầy đủ trước khi bạn cố gắng truy cập vào các bộ phận của nó. Một ngoại lệ đáng chú ý đối với điều này là khi bạn trực tiếp đưa dịch vụ vào một dịch vụ khác, tại thời điểm đó container chứa chắc chắn rằng dịch vụ đó đã được nạp trước.

Bạn có thể thấy hiệu ứng của việc này bằng cách thực hiện hai dịch vụ. A và B. A được thông qua B, và B được thông qua A. Bây giờ bạn có một tham chiếu vòng tròn. Thay vào đó, nếu bạn chuyển vùng chứa vào cả A và B, bạn không thể truy cập A từ B và B từ A mà không gặp sự cố.

8

Vì Symfony 2.6 vấn đề này nên được khắc phục. Một yêu cầu kéo vừa được chấp nhận vào tổng thể. Vấn đề của bạn được mô tả ở đây. https://github.com/symfony/symfony/pull/11690

Kể từ Symfony 2.6, bạn có thể tiêm security.token_storage vào người nghe của mình. Dịch vụ này sẽ chứa mã thông báo được sử dụng bởi SecurityContext trong < = 2.5. Trong 3.0 dịch vụ này sẽ thay thế hoàn toàn SecurityContext::getToken(). Bạn có thể xem danh sách thay đổi cơ bản tại đây: http://symfony.com/blog/new-in-symfony-2-6-security-component-improvements#deprecated-the-security-context-service

Ví dụ sử dụng trong 2.6:

cấu hình của bạn:

services: 
    my.listener: 
     class: EntityListener 
     arguments: 
      - "@security.token_storage" 
     tags: 
      - { name: doctrine.event_listener, event: prePersist } 


Listener bạn

use Doctrine\ORM\Event\LifecycleEventArgs; 
use Symfony\Component\DependencyInjection\ContainerInterface; 
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; 

class EntityListener 
{ 
    private $token_storage; 

    public function __construct(TokenStorageInterface $token_storage) 
    { 
     $this->token_storage = $token_storage; 
    } 

    public function prePersist(LifeCycleEventArgs $args) 
    { 
     $entity = $args->getEntity(); 
     $entity->setCreatedBy($this->token_storage->getToken()->getUsername()); 
    } 
} 
1

Bạn nên luôn luôn cố gắng tránh tiêm chứa trực tiếp đến dịch vụ của bạn.

Tôi nghĩ giải pháp tốt nhất có thể cho vấn đề «tham chiếu vòng tròn» cũng như các vấn đề hiệu suất có thể có, sẽ sử dụng tính năng «Lazy Services» có sẵn bắt đầu từ Symfony 2.3.

Chỉ cần đánh dấu bạn phụ thuộc là lazy trong cấu hình vùng chứa dịch vụ của bạn và cài đặt ProxyManager Bridge (tìm chi tiết trong tài liệu Dịch vụ lười biếng ở trên).

Tôi hy vọng điều đó sẽ giúp, cổ vũ.

+0

Điều này đã giúp tôi trong trường hợp của tôi. Nhưng thật kỳ lạ khi thư viện 'ocramius/proxy-manager' (cần thiết cho tính năng này có thể sử dụng) yêu cầu hai thư viện zendframework. Có tính đến những phụ thuộc này tôi nghi ngờ rằng việc sử dụng tải chậm cho các biểu đồ dịch vụ không quá lớn sẽ mang lại lợi thế về tốc độ .. – Arkemlar

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