2012-01-03 14 views
12

यहां 2 प्रश्न थे जो पूरे सेवा कंटेनर को इंजेक्शन देने के लिए इसे हल करना चाहिए। लेकिन सवाल ... नीचे (ध्यान दें अंतर के बीच की कोशिश 2 & 3) देखें ...सुरक्षा संदर्भ इंजेक्शन करते समय परिपत्र संदर्भ (इकाई श्रोता) कक्षा

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

Curcular संदर्भ का प्रयास करें। ठीक है ...

प्रयास करें 2

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

परिपत्र संदर्भ (क्यों?, मैं कंटेनर की तरह कोशिश 3 में मैं छोड़कर गया सुरक्षा संदर्भ केवल इंजेक्शन लगाने हूँ)

public function __construct(ContainerInterface $container) { 
    $this->container = $container; 
} 
आज़माएं

काम करता है।

+0

कृपया पूरा कोड उदाहरण पोस्ट करें। सर्कुलर रेफ आमतौर पर इसका मतलब है कि आप ऐसी सेवा इंजेक्ट करने की कोशिश कर रहे हैं जो पहले से ही उसी वर्ग में किसी अन्य तरीके से इंजेक्शन दे रही है। (सबसे लोकप्रिय समस्या सिद्धांत श्रोताओं में इकाई प्रबंधक है) – Inoryy

उत्तर

25

ऐसा इसलिए होता है क्योंकि आपका सुरक्षा संदर्भ इस श्रोता पर निर्भर करता है, संभवत: इकाई प्रदाता में इंजेक्शन वाले इकाई प्रबंधक के माध्यम से। सबसे अच्छा समाधान श्रोता में कंटेनर इंजेक्ट करना और सुरक्षा संदर्भ को आलसी रूप से एक्सेस करना है।

मैं आम तौर पर पूरे कंटेनर को एक सेवा में इंजेक्शन देना पसंद नहीं करता हूं, लेकिन सिद्धांत श्रोताओं के साथ अपवाद करता हूं क्योंकि वे उत्सुकता से लोड होते हैं और इसलिए जितना संभव हो उतना आलसी होना चाहिए।

+0

हम्म, कुछ समझ में आता है, लेकिन मुझे नहीं मिलता कि 3 सफल होने पर "कोशिश करें 2" विफल होना चाहिए। हां, यह "आलसी" है लेकिन एक आवृत्ति चर किसी अन्य वर्ग के कामकाज को गड़बड़ कर देगा? हम्म ... –

+0

कंटेनर यह ट्रैक करता है कि बनाने की प्रक्रिया में यह कौन सी सेवाएं है। यदि इन सेवाओं में से किसी एक के लिए 'get() 'कहा जाता है, तो यह पहले से ही बनाने की प्रक्रिया में है, एक परिपत्र संदर्भ अपवाद फेंक दिया गया है। यही कारण है कि जब आप कन्स्ट्रक्टर के अंदर से सुरक्षा संदर्भ के लिए कॉल करते हैं तो आपको यह अपवाद मिल रहा है, लेकिन अन्यथा नहीं। जब निर्माता को कंटेनर कहा जाता है तो सुरक्षा संदर्भ बनाने पर पहले से ही काम कर रहा है। –

+1

कंटेनर इंजेक्शन कभी नहीं «सबसे अच्छा समाधान» है। मुझे लगता है कि बेहतर तरीका «आलसी सेवाओं» का उपयोग करना होगा। –

1

कारण "2" विफल रहता है और "3" करता है नहीं है, क्योंकि विकल्प 2 में आप कंटेनर से तुरंत सुरक्षा संदर्भ का उपयोग करने के लिए जब यह संभावना अभी तक तैयार नहीं हुआ है कोशिश कर रहे हैं।

के रूप में सबसे अच्छा मैं बता सकता हूँ, Symfony2 config के माध्यम से पार्स करता है और अन्य के बाद सेवा एक को दर्शाता है और उसके बाद शेष अनुरोध से निपटने पर ले जाता है।

इसका मतलब है कि आप कंटेनर के विभिन्न हिस्सों तक जरूरी नहीं पहुंच सकते हैं क्योंकि यह उन्हें एक अलग क्रम में लोड कर सकता है। तो आपके पास कंटेनर में मेमोरी पॉइंटर है, और उसे स्टोर करें, लेकिन फिर फ्रेमवर्क को पूर्ण कंटेनर बनाने के पहले इसे पूरा करने से पहले इसे पूरा करने दें। इसका एक उल्लेखनीय अपवाद यह है कि जब आप सीधे किसी अन्य सेवा में सेवा इंजेक्ट करते हैं, तो उस बिंदु पर कंटेनर यह सुनिश्चित कर रहा है कि उस सेवा को पहले लोड किया गया हो।

आप दो सेवाओं को बनाकर इसका प्रभाव देख सकते हैं। ए और बी ए बी पास किया गया है, और बी बी पारित किया गया है। अब आपके पास एक परिपत्र संदर्भ है। यदि आप इसके बजाय कंटेनर को ए और बी दोनों में पारित करते हैं, तो आप किसी समस्या के बिना ए से बी और बी तक ए तक नहीं पहुंच पाए।

8

सिम्फनी 2.6 के रूप में इस मुद्दे को ठीक किया जाना चाहिए। एक पुल अनुरोध अभी मास्टर में स्वीकार कर लिया गया है। आपकी समस्या यहां वर्णित है। https://github.com/symfony/symfony/pull/11690

सिम्फनी 2.6 के रूप में, आप अपने श्रोता में security.token_storage इंजेक्ट कर सकते हैं। < = 2.5 में SecurityContext द्वारा उपयोग की जाने वाली टोकन में इस सेवा में टोकन होगा। 3.0 में यह सेवा SecurityContext::getToken() को पूरी तरह से बदल देगी। http://symfony.com/blog/new-in-symfony-2-6-security-component-improvements#deprecated-the-security-context-service 2 में

उदाहरण उपयोग: आप एक बुनियादी परिवर्तन सूची यहाँ देख सकते हैं।6:

आपका विन्यास:

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


आपका श्रोता

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

तुम हमेशा अपनी सेवाओं के लिए सीधे कंटेनर इंजेक्शन लगाने से बचने के लिए प्रयास करना चाहिए।

मुझे लगता है कि «परिपत्र संदर्भ» समस्या के साथ-साथ संभावित प्रदर्शन समस्याओं के लिए सबसे अच्छा संभव समाधान, सिम्फनी 2.3 से शुरू होने वाली सुविधा «Lazy Services» सुविधा का उपयोग करना होगा।

बस अपनी सेवा कंटेनर कॉन्फ़िगरेशन में lazy के रूप में निर्भरता को चिह्नित करें और प्रॉक्सी मैनेजर ब्रिज इंस्टॉल करें (ऊपर आलसी सेवा प्रलेखन में विवरण देखें)।

मुझे उम्मीद है कि मदद करता है, चीयर्स।

+0

इससे मुझे मेरे मामले में मदद मिली। लेकिन यह अजीब तरह का है कि 'ओक्र्रामियस/प्रॉक्सी-मैनेजर' लाइब्रेरी (इस सुविधा के लिए जरूरी है) को दो ज़ेंडफ्रेमवर्क लाइब्रेरी की आवश्यकता होती है। इन निर्भरताओं को ध्यान में रखते हुए मुझे संदेह है कि बहुत बड़ी सेवा ग्राफ के लिए आलसी लोडिंग का उपयोग गति लाभ देता है .. – Arkemlar

संबंधित मुद्दे