2012-07-13 32 views
9

Sto cercando un modo per utilizzare Symfony 2 Dependency Injection component con il nuovo PHP 5.4 traits.Symfony 2: dipendenza dipendenza e tratti

Per fare una lunga storia breve (non così breve, in realtà), il mio progetto ha disgiunto le classi di vista che hanno tutte un proprio costruttore specifico. Ogni View può utilizzare zero o più vista aiutanti, che sono definiti come tratti:

trait TranslatorHelper 
{ 
    /** 
    * @var Translator 
    */ 
    protected $translator; 

    /** 
    * @param Translator $translator 
    */ 
    protected function setTranslator(Translator $translator) 
    { 
     $this->translator = $translator; 
    } 

    /** 
    * @param string $text 
    * @return string 
    */ 
    public function translate($text) 
    { 
     return $this->translator->translate($text); 
    } 
} 

-

class UserEditView extends AbstractView 
{ 
    use TranslatorHelper; 

    public function __construct(User $user, UserEditForm $form) 
    { 
     // ... 
    } 
} 

Mi piacerebbe avere un metodo in mio controller, renderView(), che esegue setter iniezione a base di tutti i tratti utilizzati dalla classe View, prima del rendering della vista:

class Controller 
{ 
    public function renderView(View $view) 
    { 
     // Check what traits are used by $view, and inject their dependencies 
     // {...} 


     // Then render the View 
     return $view->render(); 
    } 
} 

Qualche idea su come fare questo con il 012 Componente?

Il problema principale è ovviamente che le viste non verranno create dal contenitore DI ma possono essere create ovunque nel flusso dell'applicazione. È solo prima di essere reso che le dipendenze devono essere iniettate.

Un'ultima nota: non sono legato al componente Symfony. Sarebbe apprezzato anche qualsiasi vantaggio su un altro contenitore DI.

+0

È possibile provare DI con AOP: https://github.com/schmittjoh/JMSAopBundle/blob/master/Resources/doc/index.rst per iniettare automaticamente servizi mediante annotataione di proprietà e argomenti. – lisachenko

+0

Il problema è che volevo mantenere generici gli helper di visualizzazione (come ad esempio 'TranslatorHelper'), quindi idealmente non dovrebbero contenere l'id specifico del progetto delle dipendenze nel contenitore. – Benjamin

risposta

4

Penso che i tratti non siano pensati per essere usati per fare DI in questo modo. Quello che farei in uno scenario simile è usare l'iniezione del costruttore (o anche il setter andrebbe bene, anche se il costruttore più difficile è meglio quando possibile) nella classe di visualizzazione che implementa i tratti per iniettare direttamente i servizi necessari.

Se si pensa che i tratti implementati da una classe vengono definiti staticamente prima dell'esecuzione dell'applicazione, non è quindi necessario esaminare i tratti per eseguire un'iniezione dinamica. Saprai quali servizi ti occorrono prima di correre, pensa solo a come se fossero interfacce con un metodo concreto.

+0

Ricevo il tuo punto, tuttavia la mia preoccupazione è che voglio mantenere il costruttore View libero da qualsiasi dipendenza specifica di Helper (voglio che il controller usi esplicitamente il costruttore View per passare solo le variabili necessarie alla vista stessa, senza dover preoccuparsi per gli aiutanti). Inoltre, avrò probabilmente centinaia di classi View, tutte usando gli stessi ~ 3 view helper. Quindi preferirei essere in grado di iniettare in base al nome di Trait. Per esempio, mi piacerebbe definire nella mia configurazione che tutte le classi che usano la caratteristica 'TranslatorHelper' utilizzerebbero il Traduttore puntato dalla chiave del contenitore' translator'. – Benjamin

+3

In tal caso, ciò che si potrebbe fare è usare la codifica DI: definire un tag e un passaggio del compilatore che registri faccia la giusta dipendenza setter per ogni tratto di helper. Alcuni documenti sull'uso avanzato di DIC (come i passaggi e i tag del comiler) sono stati recentemente rilasciati sulla documentazione di Symfony. Non è automaticamente l'iniezione basata sul tratto (penso che l'unico modo per farlo sarebbe usare il riflesso che è piuttosto lento) ma è abbastanza ordinato e pulito. –