Zend FR

Consultez la FAQ sur le ZF avant de poster une question

Vous n'êtes pas identifié.

#1 16-04-2012 16:51:11

Orkin
Administrateur
Lieu: Paris
Date d'inscription: 09-12-2011
Messages: 1261

ZF2, layout & variable "globales"

Ce message est tiré d'une conversation mail entre Bakura et moi, du coup j'en fait profiter tout le monde pour que ça servent à ceux qui en auront besoin.

Bonjour,

Dans mon application, lorsqu'un utilisateur est authentifié, je ne stock en session que son id. Tous mes contrôleurs étendent d'une classe abstraite GenericController qui étend ActionController. Dans le constructeur de mon GenericController j'injecte l'entity manager de Doctrine via le DI.

Dans ce constructeur, je test si l'utilisateur est authentifié ($authentificationService->hasIdentity()) et si c'est le cas je fais une requête pour retrouver le membre via l'id. Je stock ensuite ceci dans un attribut de ma classe GenericController, de cette façon, tous mes contrôleurs ont l'information du membre avec les liens des entity etc ...

J'ai choisi cette solution parce que je veux qu'en cas de ban, modification en live etc ... que les informations du membre soient mise à jour à chaque requête. Jusque là tout fonctionne à merveille.

Mon soucis est donc d'afficher les informations utilisateur, en soit ça serait pas compliqué je le transmet à la vue depuis mon contrôleur et c'est gagné. Sauf que je suis parti dans l'idée d'avoir deux layout : un pour le site lorsque l'utilisateur est authentifié et un autre lorsque l'utilisateur est non authentifié.

En utilisant une aide de vue que j'appelle directement depuis mon layout je pourrais aller récupérer l'id de l'utilisateur de la session et faire une requête pour récupérer ses informations. Le problème c'est que pour chaque requête http ça me fait 2 requêtes SQL pour récupérer les informations du membre alors qu'une seule devrait suffire.

Le problème est que je ne sais pas comment faire en sorte de transmettre le membre que j'ai dans mon contrôleur à mon layout de façon à ce que ça se généralise à l'ensemble de mes pages et je me vois mal appeler mon aide de vue pour les infos du membre sur chaque page ... Ca fait pas trop optimisé ni très propre.

J'ai donc plusieurs solutions qui ne me conviennent pas :
- Aide de vue qui va faire une requête => nb requêtes SQL x 2 et manipulation de 2 objets différents
- Passer le membre en paramètre à ma vue et le passer de nouveau en paramètre d'appel à mon aide de vue => signifie dupliquer le code sur toutes les pages

Solution qui me semble idéale
- Passer le membre en paramètre directement à mon layout qui le passerait en paramètre à mon aide de vue.

Merci d'avance

Orkin

Dernière modification par Orkin (16-04-2012 16:53:47)

Hors ligne

 

#2 16-04-2012 16:53:28

Orkin
Administrateur
Lieu: Paris
Date d'inscription: 09-12-2011
Messages: 1261

Re: ZF2, layout & variable "globales"

Réponse de Bakura :

Salut,

Est-ce que tu as compris un peu comment fonctionne les layout dans ZF 2 ? C'est très différent de comment c'était implémenté sous ZF1, puisqu'à l'époque il y avait des objets "Vue" et tout un module "Layout" (Zend\Layout).

Sur ZF2, un layout ou une vue sont des "ViewModels", c'est-à-dire un objet qui dispose de plusieurs informations permettant de créer le code HTML : le nom du template à utiliser, les variables locales à ce template et des viewModels enfant. Le layout au sens ZF2 n'est rien de plus qu'un ViewModel qui a des enfants.

Imagine un cas simple : un layout, et une action dont le template est test.phtml. Automatiquement, lorsque tu actives le mécanisme de layout, le layout sera TOUJOURS le view model "racine". Dans ce cas, le layout aura comme enfant un seul viewModel : le view model contenant toutes les informations pour dessiner la vue test.phtml.

Ce qui signifie que lorsque Zend va faire le rendu, il va partir des feuilles (à savoir, "dessiner" la vue test.phtml), puis dessiner la vue layout.phtml et y injecter le code de la vue test.phtml.


Dans ton cas, l'idée consiste tout simplement à ajouter une variable locale à ton layout (ton utilisateur). Or depuis la bêta 3 il y a un plugin de contrôleur qui s'appelle "Layout" et qui te permet justement de récupérer ce layout.

Il te suffit donc dans la fonction de ton contrôleur ou tu charges ton utilisateur, de faire :

$layout = $this->layout();
$layout->user = $user;


Puis dans ton layout.phtml :

<?php echo $this->monAideDeVue($user); ?>

Hors ligne

 

#3 16-04-2012 16:59:12

bakura
Administrateur
Date d'inscription: 30-01-2010
Messages: 353

Re: ZF2, layout & variable "globales"

Et ta deuxième question :

Aucun soucis je transporte le topic et j'y apporte la réponse à la suite wink.

En fait j'ai bien 2 layout mais disons que dans mon layout la partie $this->content correspond à l'affichage des enfant fils si j'ai bien compris non ? Parce que en fait j'ai besoin d'afficher ça directement dans la partie content. Du coup ça complique un peu la chose ... Je reporte ça sur le forum comme ça t'y répond où tu veux wink



Réponse :

Je suis pas sur d'avoir compris. Tu souhaites appeler ton aide de vue qui utilises un objet user dans la vue "enfant" ?

Hors ligne

 

#4 16-04-2012 16:59:54

Orkin
Administrateur
Lieu: Paris
Date d'inscription: 09-12-2011
Messages: 1261

Re: ZF2, layout & variable "globales"

bakura a écrit:

Est-ce que tu as compris un peu comment fonctionne les layout dans ZF 2 ? C'est très différent de comment c'était implémenté sous ZF1, puisqu'à l'époque il y avait des objets "Vue" et tout un module "Layout" (Zend\Layout).

Faut croire que je n'avais pas compris ça de cette façon. Du coup si j'ai bien compris on peut très bien avoir une application sans layout et dans ce cas seul la vue de l'action sera affichée (dans l'exemple, test.phtml) ?

Je viens de tester sans utiliser d'aide de vue voir si mon objet était bien passé en paramètre et je me récupère un "NULL" avec un var_dump.

J'ai bien ajouté comme tu me l'as dit dans le contrôleur :

Code:

[lang=php]
// Classe volontairement simplifiée
abstract class GenericController extends ActionController {

protected $_membre;

public function __construct(EntityManager $em) {
$authenticationService = new AuthenticationService();

        // Action à faire qu'en cas de session utilisateur
        if ($authenticationService->hasIdentity()) {
            $id = $authenticationService->getIdentity();
            
            $membreService = new MembreService($em);
            $membre = $membreService->getMembreById($id);

            $this->_membre = $membre;
            
            $layout = $this->layout();
            $layout->membre = $membre;
}
}

J'ai du encore louper un truc :s

bakura a écrit:

Tu souhaites appeler ton aide de vue qui utilises un objet user dans la vue "enfant" ?

Non comme c'est actuellement c'est bien mais je suis bien curieux de savoir si c'est possible de faire ça. Ca pourrait peut être servir ^^.

Dernière modification par Orkin (16-04-2012 17:03:41)

Hors ligne

 

#5 16-04-2012 17:08:40

bakura
Administrateur
Date d'inscription: 30-01-2010
Messages: 353

Re: ZF2, layout & variable "globales"

En fait je me souviens plus si ZF2 effectue un extract afin de pouvoir utiliser les variables sans le $this dans la vue. Dans le doute, fait $this->membre dans ta vue. Et vérifie aussi dans le constructeur que $membre n'est pas à NULL juste après l'avoir chargé, on sait jamais.

Hors ligne

 

#6 16-04-2012 17:14:37

Orkin
Administrateur
Lieu: Paris
Date d'inscription: 09-12-2011
Messages: 1261

Re: ZF2, layout & variable "globales"

Alors non ma variable n'est pas null. Dans mon contrôleur j'ai bien $membre et $layout->membre qui sont renseignée.

Dans ma vue index.phtml j'ai fait un var_dump($this->membre) j'ai null, et pareil dans le layout. Avec seulement $membre dans la vue et/ou layout ça plante (variable inexistante).

Par curiosité j'ai fait un var_dump($layout) et ma variable membre n'est pas présente.

EDIT : j'ai essayé de passer par :
$layout->setVariable('membre', $membre) => même résultat
$layout->setVariables(array('membre' => $membre)) => quand je fais un var_dump($layout->getVariables()) j'ai bien ma variable de visible mais n'est pas transmise à la vue.

Dernière modification par Orkin (16-04-2012 17:37:39)

Hors ligne

 

#7 17-04-2012 10:08:48

bakura
Administrateur
Date d'inscription: 30-01-2010
Messages: 353

Re: ZF2, layout & variable "globales"

(J'essayerai de regarder un peu plus tard, il faudrait vérifier que Zend ne réinitialise pas les variables du layout à un moment donné.)

Hors ligne

 

#8 17-04-2012 11:42:02

Orkin
Administrateur
Lieu: Paris
Date d'inscription: 09-12-2011
Messages: 1261

Re: ZF2, layout & variable "globales"

Plop, j'ai résolu le problème. J'ai eu l'explication de la part de mwop.

Donc l'explication qu'il m'a donné c'est que dans le constructeur du contrôleur, le layout n'est pas encore accessible ce qui explique pourquoi ça ne fonctionne pas comme il faudrait. En testant dans une action quelconque ça fonctionne très bien. Le soucis est donc de faire en sorte que le code soit exécuté à chaque action sans avoir à le dupliquer.

La solution, les events. C'est une partie du framework qui semble assez puissante et dont je n'avais pas mesuré l'importance jusqu'à maintenant.

Il faut donc faire comme ceci dans le constructeur :

Code:

[lang=php]
$this->events()->attach('dispatch', array($this, 'onDispatch'), 10);
//'dispatch' => le type d'event j'imagine
//$this => où trouver la méthode (je pense)
// 'onDispatch' le nom de la methode
// 10 => priorité

public function onDispatch($e) {
        $this->layout()->membre = $this->_membre;
    }

Voila. Du coup je suis à la recherche d'informations pour comprendre comment fonctionne ces events smile.

Hors ligne

 

#9 22-06-2012 00:29:35

djiwhy
Nouveau membre
Date d'inscription: 22-06-2012
Messages: 1

Re: ZF2, layout & variable "globales"

Bonjour,

N'ayant pas réussi à faire fonctionner le code précédent (en l'adaptant pour récupérer ici le nom du contrôleur en cours dans le layout), j'ai donc procédé ainsi:

Code:

[lang=php]namespace Application\Controller;

use Zend\Mvc\Controller\ActionController;
use Zend\Mvc\MvcEvent;

class MyActionController extends ActionController
{
  public function execute(MvcEvent $e)
  {
    $this->layout()->controller = $e->getRouteMatch()->getParam('controller');

    return ActionController::execute($e);
  }
}

Pour info, j'avais d'abord essayé de faire fonctionner sans succès le code suivant:

Code:

[lang=php]namespace Application\Controller;

use Zend\Mvc\Controller\ActionController;
use Zend\Mvc\MvcEvent;

class MyActionController extends ActionController
{
  public function __construct() {
    $this->events()->attach(MvcEvent::EVENT_DISPATCH, array($this, 'onDispatch'), 10);
  }

  public function onDispatch(MvcEvent $e) {
    $this->layout()->controller = $e->getRouteMatch()->getParam('controller');
  }
}

Apparemment, le "onDispatch" n'était pas lancé, sans que je sache pourquoi...

Hors ligne

 

#10 27-10-2012 08:14:03

mtcocktail
Membre
Date d'inscription: 20-09-2012
Messages: 71

Re: ZF2, layout & variable "globales"

Ah bah j'ai la même problèmatique. J'arrivais pas a comprendre, maintenant je comprend pourquoi mon addchild ne marche pas pour un autre block de mon layout racine. Par contre j'ai pas compris la solution proposé sad

Hors ligne

 

#11 27-10-2012 09:29:28

mtcocktail
Membre
Date d'inscription: 20-09-2012
Messages: 71

Re: ZF2, layout & variable "globales"

J'y suis presque en passant par l'event Manager, je re-post quand j'ai la solution.

Hors ligne

 

#12 27-10-2012 17:28:11

mtcocktail
Membre
Date d'inscription: 20-09-2012
Messages: 71

Re: ZF2, layout & variable "globales"

Première solution trouvé sans passer par l'event manager permettant de faire un addChild dans le controlleur d'un module et d'affecter la vue enfant à un block déclaré dans le layout parent :

Sur le layout de l'application :

/Application/view/layout/layout.phtml :
...
<? echo $this->menu; ?>
...
<? echo $this->content; ?>
...

Donc $this->content sera remplit par l'objet view de notre controller d'un autre module.

Le hic que j'avais c'était de pouvoir dans mon contrôleur remplir $this->menu qui est dans mon layout racine.

Et bien tous simplement on peut dans le controller faire la chose suivante :

Code:

public function indexAction()
    {
      $view = new ViewModel();
      $menu = new ViewModel();
      $menu->setTemplate('content/menu');

      $view->addChild($menu,'menu');
        
      return $view;
}

Et dans mon template /view/mon_module/mon_module/index.phtml on peut accéder au layout parent avec la méthode $this->layout. On peut donc affecter dans la variable de notre layout la vue enfant que l'on a attaché dans notre controller.

Il suffit donc de faire au début du template :

Code:

<?php
$this->layout()->menu = $this->menu;
?>

Maintenant si on veut faire ça de façon automatique pour toutes les actions c'est là que l'event manager et la fonction ondispatch rentre en jeux. Mais ça je n'ai pas encore réussi.

Hors ligne

 

#13 29-10-2012 22:38:00

Bouks
Membre
Lieu: Paris
Date d'inscription: 31-08-2012
Messages: 241

Re: ZF2, layout & variable "globales"

Pour avoir l'utilisateur dans le layout (et tous les partials par transmission du helper).
Bien sûr on peut aussi passer d'autres variables (données métiers, résultat d'autres controllers, modules...) au layout (éventuellement changer le layout, je n'ai pas essayé).

J'ai simplifié ma fonction pour n'avoir que ce qui nous intéresse. Ca se passe donc dans le parent des controlleurs concernés.

Code:

[lang=php]
public function setEventManager(EventManagerInterface $events)
    {
        parent::setEventManager($events);
        $controller = $this;
        $events->attach('dispatch', function ($e) use ($controller) {

// fonction qui récupère mon service d'authentication, à adapter
                        $authentication = $controller->getAuthentication();

                    $controller->layout()->setVariables(array(
// getUser est une fonction personnelle
                        'user' => $authentication->getUser(),
                        'hasIdentity' => $authentication->hasIdentity()
                    ));
                }, 100
        );

    }

22914720

Hors ligne

 

#14 24-11-2012 14:53:01

Orkin
Administrateur
Lieu: Paris
Date d'inscription: 09-12-2011
Messages: 1261

Re: ZF2, layout & variable "globales"

Plop, je me permet de remonter ce sujet car il y a quelque chose qui me chagrine dans ton code Bouks et il va y avoir des nouveautés dans les prochaines versions stables du ZF2 à partir de la 2.1.0. En effet pourquoi t’embêter à passer à ton layout un boolean pour savoir si l'utilisateur est connecté ou non alors que tu peux utiliser une aide de vue pour le faire.

De plus dans la version ZF2.1.0 il y a une aide de vue par défaut qui récupère tout ce qu'il faut. Elle retourne null dans le cas où personne n'est connecté et le user dans le cas où il est connecté smile. Et ceci fonctionne parfaitement avec doctrine.

L'authentification service via doctrine gère vraiment bien la chose. Il va s'occuper se stocker tout seul en session uniquement l'id et retourner l'utilisateur en faisant la requête tout seul. Il y a juste un problème lorsque l'on a un adapter custom qui fait des jointures (à tester si ça le fait lorsqu'on les fait via annotations) mais il refait la requête à chaque appelle. Il faut donc faire un test si on a déjà chargé l'utilisateur dans la requête http smile.

Hors ligne

 

Pied de page des forums

Propulsé par PunBB
© Copyright 2002–2005 Rickard Andersson
Traduction par punbb.fr

Graphisme réalisé par l'agence Rodolphe Eveilleau
Développement par Kitpages