2013-03-31 24 views
5

Attualmente sto sviluppando un sito Web multilingue. Per la parte multilingua uso traduttore/poedit. Memorizzo la lingua selezionata in sessione. Funziona bene.Zend Framework 2 passa variabile ai modelli

Module.php:

public function onBootstrap(MvcEvent $e) 
{ 
    // ... 

    $session = new Container('base'); 

    if ($session->language !== NULL) { 
     $e->getApplication()->getServiceManager()->get('translator')->setLocale($session->language); 
    } 
} 

azione per l'impostazione della lingua in un controllore:

public function setLanguageAction() 
{ 
    $language = $this->params()->fromRoute('language'); 

    if (isset($this->languages[$language])) { 

     $session = new Container('base'); 

     if ($language == 'en') { 
      $session->language = NULL; 
     } else { 
      $session->language = $language; 
     } 
    } 

    return $this->redirect()->toRoute('home'); 
} 

Nel module.config.php l'impostazione internazionale predefinita è impostata su en.

Come ho detto tutto funziona bene, tranne che per una cosa.

Memorizzo alcuni dati dipendenti dalla lingua anche in DB, quindi nei miei modelli ho bisogno di sapere qual è la lingua corrente. La lingua corrente è necessaria per altri scopi anche nei modelli.

Così ho includere il seguente codice nella funzione costrutto di ogni modello:

$session = new Container('base'); 

if ($session->language !== NULL) { 
    $this->language = $session->language; 
} else { 
    $this->language = 'default'; 
} 

penso che non è la soluzione migliore. Ho troppi modelli per includere sempre questo codice.

Vorrei sapere se c'è una soluzione per passare una variabile $ lingua automaticamente a tutti i miei modelli per esempio da Module.php funzione/getServiceConfig:

public function getServiceConfig() 
{   
    $session = new Container('base'); 

    return array(
     'factories' => array(
      'Application\Model\SomeThing' => function($sm) { 
       $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter'); 
       $c = new SomeThing($dbAdapter); 
       $c->language = $session->language; 
       return $c; 
      } 
     ) 
    ); 
} 

Naturalmente questo non sta funzionando, ma sarebbe bello poter fare qualcosa di simile in questo modo, o una soluzione più generale, dove non è necessario assegnare il valore della lingua corrente alla variabile di lingua di ogni modello nell'array di fabbrica (ad esempio un bootstrap comune per modelli, dove questo compito può essere svolto per tutti i modelli in un unico posto).

C'è una soluzione per il mio problema?

Grazie per il vostro aiuto!

M

risposta

4

Se non si vuole iniettare la lingua in tutti i tuoi modelli, allora mi viene in mente almeno un altro modo fuori dalla parte superiore della mia testa.

È possibile utilizzare un inizializzatore. Un inizializzatore consente fondamentalmente di eseguire attività di inizializzazione sui servizi recuperati tramite il gestore servizi. Pertanto, per utilizzare questo approccio, è necessario recuperare i modelli (almeno quelli che richiedono la lingua) tramite il gestore del servizio. Questo è facile come aggiungerli come invokable o forse fabbriche se è necessario iniettare eventuali dipendenze. Per ulteriori informazioni sugli inizializzatori, è possibile leggere lo article I wrote about the service manager (scorrere verso il basso fino alla sezione relativa agli inizializzatori).

Quindi, ciò che si può fare è fare in modo che i propri modelli implementino un'interfaccia, ad es. LanguageAwareInterface.

namespace User\Model; 

interface LanguageAwareInterface { 
    /** 
    * Gets the language 
    * 
    * @return string 
    */ 
    public function getLanguage(); 

    /** 
    * Sets the language 
    * 
    * @param string $language 
    */ 
    public function setLanguage($language); 
} 

Quindi è possibile eseguire le seguenti operazioni nel modello.

namespace User\Model; 

class MyModel implements \User\Model\LanguageAwareInterface { 
    /** 
    * @var string $language The current language 
    */ 
    protected $language; 

    /** 
    * Gets the language 
    * 
    * @return string 
    */ 
    public function getLanguage() { 
     return $this->language; 
    } 

    /** 
    * Sets the language 
    * 
    * @param string $language 
    */ 
    public function setLanguage($language) { 
     $this->language = $language; 
    } 
} 

Se lo si desidera, si può anche fare una classe astratta modello di base che ha il codice di cui sopra, o forse scrivere un semplice tratto, se si vuole evitare che si estende una classe.Quindi i tuoi modelli potrebbero estendere questa classe base, ma questo dipende da quanti dei tuoi modelli hanno effettivamente bisogno di lavorare con la lingua corrente.

Ora per l'inizializzatore. Nel mio articolo ho un esempio di come aggiungerlo con le chiamate al metodo, ma è probabile che lo si voglia fare nel file di configurazione (forse nel modulo Application se si sta utilizzando l'applicazione Zend Skeleton). È possibile restituire un array (o puntare a un file di configurazione) dalla classe Module del modulo nel metodo getServiceConfig() oppure aggiungerlo al file YourModule/config/module.config.php sotto la chiave service_manager. La documentazione ufficiale non fornisce alcun esempio di ciò; infatti, gli inizializzatori sono l'unica cosa che manca. Dovrebbe, tuttavia, funzionare.

return array(
    /* Other configuration here */ 

    'service_manager' => array(
     'initializers' => array(
      'language' => function($service, $sm) { 
       // $service is the service that is being fetched from the service manager 
       // $sm is the service manager instance 
       if ($service instanceof \User\Model\LanguageAwareInterface) { 
        $session = new \Zend\Session\Container('base'); 

        if ($session->language === null) { 
         // Fetch default language from configuration 
         $config = $sm->get('Config'); 

         $session->language = $config['translator']['locale']; 
        } 

        $service->setLanguage($session->language); 
       } 
      }, 
     ), 
    ), 
); 

I controlli di inizializzazione di cui sopra ogni oggetto che viene recuperata dal gestore del servizio per vedere se si implementa l'interfaccia che abbiamo creato in precedenza. Se lo fa, la lingua può essere iniettata. Nel mio esempio, controllo per vedere se è impostato nella sessione e, in caso contrario, lo preleva dalla configurazione. Potrebbe essere necessario modificare la logica in base alle proprie esigenze. Si noti che l'inizializzatore verrà eseguito ogni in cui si recupera un oggetto dal gestore servizi e quindi si aggiunge un po 'di sovraccarico. Questo, tuttavia, non è significativo perché stiamo facendo solo un semplice controllo di tipo quando il servizio non implementa l'interfaccia. Inoltre, i servizi sono condivisi di default, il che significa che un servizio verrà istanziato una sola volta; le richieste successive per lo stesso servizio, quindi, riutilizzeranno quella precedentemente istanziata. Questo aiuta a limitare ulteriormente il sovraccarico.

0

Immagino che si possa prima registrare il modello di sessione nel gestore servizi nel Modulo.php di qualunque modulo si desideri in modo che sia globalmente disponibile e utilizzare questo servizio ogni volta che è necessario accedere alla sessione.

public function getServiceConfig() 
{   
    return array(
     'factories' => array(
      'AppSession' => function($sm) { 
        $session = new \Path\To\Session(); 
        $session->doSomething(); 
        return $session; 
      } 
     ) 
    ); 
} 

Quando si registrano i vari modelli nell'intera applicazione nel gestore servizi, immettere il servizio di sessione.

public function getServiceConfig() 
{   
    return array(
     'factories' => array(
      'Application\Model\SomeThing' => function($sm) { 
       $c = new SomeThing(); 
       // You will have to create the set and get functions. 
       $c->setDbAdapterService($sm->get('Zend\Db\Adapter\Adapter')); 
       $c->setSessionService($sm->get('AppSession')); 
       return $c; 
      } 
     ) 
    ); 
} 

E sul controller troppo, potrebbe avere più senso per iniettare la sessione fin dall'inizio in modo che la sessione è pronto e in attesa per voi.

Nella tua module.config.php ...

return array(
    'controllers' => array(
     'factories' => array(
      'Application\Controller\Something' => function ($sm) { 
       $locator = $sm->getServiceLocator(); 
       $c = new Application\Controller\SomethingController(); 
       $c->setSessionService($locator->get('AppSession')); 
       return $c; 
      }, 
     ), 
    ), 
    'router' => array(
     'routes' => array(
      'myroute' => array(
       'type' => 'Zend\Mvc\Router\Http\Segment', 
       'options' => array(
        'route' => '[/:action]', 
        'defaults' => array(
         'controller' => 'Application\Controller\Something', 
         'action'  => 'index', 
        ), 
       ), 
      ), 
     ), 
    ), 
);