Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

  1. #1
    Nouveau membre du Club
    Écrire une jointure entre plusieurs tables avec le modèle MVC et Zend en PHP5
    Bonjour,

    J'ai lu les cours sur Zend et le MVC
    je vois comment faire des select.

    Mais je vois pas comment faire des jointures...
    j'ai par exemples 3 tables:
    table 1: id_ville, nom_ville, adresse
    table 2: id_region, nom_region, note
    table 3: id_ville, id_region

    J'ai fait des modèles pour mes tables:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    <?php
    class Ville extends Zend_Db_Table_Abstract
    {
    	protected $_name = 'table1_ville';
     
    	protected $_dependentTables = array('table3_RegionVille', 'Region');
    }?>
     
    <?php
    	class Region extends Zend_Db_Table_Abstract
    	{
    		protected $_name = 'table2_region';
    		protected $_dependentTables = array(
    			'table3_RegionVille');
    	}
     
    ?>
     
    <?php
    	class table3_RegionVille extends Zend_Db_Table_Abstract
    	{
    	    protected $_name = 'table3_RegionVille';
     
    	    protected $_referenceMap    = array(
    	        'rule_ville' => array(
    	            'columns'           => 'id_ville',
    	            'refTableClass'     => 'table1_ville',
    	            'refColumns'        => 'id_ville'
    	        ),
    	        'rule_region' => array(
    	            'columns'           => 'id_region',
    	            'refTableClass'     => 'table2_region',
    	            'refColumns'        => 'id_region'
    	        )
    	    );
    	}
     
    ?>


    A partir de ces modèles, j'arrive à faire un select dans mon controlleur, du genre:
    controlleur.php->
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    public function indexAction()
    {
    $select = $this->table2_region->select();	       
    $this->view->table2_region=$this->table2_region->fetchAll($select);    
    $this->render();
    }


    Mais je ne vois pas comment faire une jointure :s


    par exemple afficher toutes les villes de chaque région... en tenant compte du MVC et de ZEND...
    car la requête sql en tant que tel ne me pose pas de probleme, j'obtiendrais un truc du genre:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    $requete="select v.id_ville, v.nom_ville from table1_ville v, table2_region r, table3_RegionVille rv where v.id_ville=rv.id_ville and rv.id_region=r.id_region group by r.id_region";


    Quelqu'un pourrait-il me montrer comment faire la jointure en tenant compte des modèles (MVC) et du framework Zend?



    Merci d'avance de votre aide

  2. #2
    Membre du Club
    Bonjour,

    Je ne suis pas un spécialiste du framework mais je pense qu'il y a plusieurs solutions à ton problème :
    je n'ai pas testé mais si tu utilise des objet Zend_Db_Table il y a des méthodes comme find qui prennent en compte les relations entre tables.
    Tu peux sinon je crois passer par un objet Zend_Db_Select qui est souple d'utilisation et dans lequel tu peux ajouter des clauses from, where etc.
    Dans le pire des cas tu peux passer n'importe quelle requète à ton adapter. Je pense que $ton_adapter->fetchAll(ta_requète) doit fonctionner.

  3. #3
    Membre expérimenté
    1) Si une ville n'appartient qu'à une région, ton modèle est incorrect : la table3 est inutile.
    2) Sinon, voici une solution à placer dans le modèle de ta table1 :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    $db = $this->getAdapter();
     
    // renvoie toutes les villes de toutes les régions        
    $select = $db->select()
        ->from('table3')
        ->joinInnerUsing('table1', 'idVille')
        ->joinInnerUsing('table2', 'idRegion')
        ->order(array('table2.nom_region', 'table1.nom_ville'));
     
    $stmt = $select->query();
    return $stmt->fetchAll();

  4. #4
    Nouveau membre du Club
    Merci pour vos réponses
    ça eclaircit plus mes idées que par rapport aux autres exemples quej'ai pu lire avant.

    Une autre requête que je n'arrive pas à implementer avec Zend et le modele MVC
    est une requete imbiqué avec un IN.

    exemple : j'ai ma table 4 (ville gagnante): id_gagnant, nom_ville, statut
    J'aimerais récuperer le nom des villes gagnantes qui se prenomme 'Aix' qui font partie de la région: "Provence"
    j'arrive à faire en sql:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    select g.nom_ville
    from table4_gagnant g
    where g.nom_ville like 'Aix'
    and g.nom_ville IN
    (select 
    select  v.nom_ville 
    from table1_ville v, table2_region r, table3_RegionVille rv 
    where r.nom_region like 'Provence'
    and v.id_ville=rv.id_ville 
    and rv.id_region=r.id_region
    )


    ps: ne faite pas attention à l'exemple en tant que tel, j'aimerais juste savoir comment traduire ça avec Zend et le modele MVC (via les modèles dans le message précédent)


    Merci d'avance de votre aide

  5. #5
    Nouveau membre du Club
    Comme je n'ai tjs pas trouvé comment faire un IN imbriqué

    j'essaye de faire autrement:

    j'utilise tjs mes modeles. J'ai ceci comme requête:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $select = $this->table3_RegionVille->select()
                 ->from(array('h_hg' => $this->table3_RegionVille))
                 ->from(array('hg' => $this->table2_region))
                 ->from(array('h' => $this->table1_ville))
                 ->where('id_region = ?', $this->region)
                 ->where('nom_ville like ?', $nom_villeville)
                 ->where('hg.id_region= h_hg.id_region')
                 ->where('h_hg.id_ville= h.id_ville');             
     
    			$stmt = $select->query();
    			return $stmt->fetchAll();


    Puis-je structurer ma requête comme cela? (à voir la doc, je suppose)
    mais il met me ceci comme erreur:
    Exception : Zend_Db_Statement_Exception Message : SQLSTATE[42000]: Syntax error or access violation: 1065 Query was empty
    Quelqu'un pourrait-il m'eclaircir?


    merci d'avance

  6. #6
    Membre expert
    Bonjour,

    Peux tu nous dire ce que renvoie un $select->__toString() ?

  7. #7
    Nouveau membre du Club
    mon select devrait réenvoyer la ville donnée en parametre d'une telle région ($this->region) si la ligne existe

  8. #8
    Membre expert
    Citation Envoyé par benja507 Voir le message
    mon select devrait réenvoyer la ville donnée en parametre d'une telle région ($this->region) si la ligne existe
    Non, ce que je voulais dire, c'est simplement peux tu ajouter par exemple les instructions :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    $sql = $select->__toString();
    var_dump($sql);

    avant $stmt = $select->query();

    Pour voir quelle requête SQL est générée par la classe Zend_Db_Table_Select...

  9. #9
    Nouveau membre du Club
    var_dump renvoie ceci: string(0) ""

    ça veut dire quoi?

  10. #10
    Membre expert
    Ca veut dire que ton objet $select (de classe Zend_Db_Table_Select) n'a pas réussi à générer la requête SQL à exécuter... d'où l'exception levée par Zend_Db_Statement.

    Si tu supprimes les clauses from et where (c'est à dire ne conserver que le $this->table3_RegionVille->select(); ), est-ce que tu as un meilleur résultat ?

  11. #11
    Nouveau membre du Club
    il met tjs la même chose

    si je retire tout les from et where
    donc il me reste:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    $select = $this->table3_RegionVille->select()
                 ->from(array('h_hg' => $this->table3_RegionVille))


    il renvoie : string(89) et la requete...

    je ne pige pas :s

    Sinon pour les requetes avec un IN en sql, personne n'aurait un exemple avec le frame work ZEND? dans la doc, il donne des exemple pour les select, from et join mais pas pour ça :s


    merci

  12. #12
    Membre expert
    Et si tu essaies de faire ta requête avec un Zend_Db_Select directement (et pas un Zend_Db_Table_Select), quelque chose comme :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    $select = $this->table3_RegionVille->getAdapter()->select()
        ->from(array('g' => 'table4_gagnant'), array('nom_ville'))
        ->join(array('v' => 'table1_ville'), 'g.nom_ville = v.nom_ville')
        ->join(array('rv' => 'table3_RegionVille'), 'v.id_ville = rv.id_ville')
        ->join(array('r' => 'table2_region'), 'rv.id_region = r.id_region')
        ->where('r.nom_region like ?', 'Provence')
        ->where('g.nom_ville like ?', 'Aix');


    Je ne sais pas si les clauses IN avec sous-requête sont supportées par le Zend Framework, mais une autre solution est d'utiliser une sous-requête dans une clause FROM :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $subSelect = $this->table3_RegionVille->getAdapter()->select()
        ->from(array('v' => 'table1_ville'), 'nom_ville')
        ->join(array('rv' => 'table3_RegionVille'), 'v.id_ville = rv.id_ville')
        ->join(array('r' => 'table2_region'), 'rv.id_region = r.id_region')
        ->where('r.nom_region like ?', 'Provence');
     
    $select = $this->table3_RegionVille->getAdapter()->select()
        ->from(array('g' => 'table4_gagnant'), array('nom_ville'))
        ->join(array('v' => $subSelect), 'g.nom_ville = v.nom_ville')
        ->where('g.nom_ville like ?', 'Aix');


    Sauf erreur, ces deux codes devraient retourner la même chose que ta requête avec IN, mais en construisant une requête de deux autres façons.

    Une bonne habitude à prendre aussi il me semble est de séparer les clauses WHERE des jointures de tables. Il me semble que le code est plus clair de cette façon (on voit de suite comment les tables sont reliées, et on voit aussi tout de suite quelles restrictions sont faites, sans avoir à fouiller dans une série de Where...).

  13. #13
    Nouveau membre du Club
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    $subSelect = $this->table3_RegionVille->getAdapter()->select()
        ->from(array('v' => 'table1_ville'), 'nom_ville')
        ->join(array('rv' => 'table3_RegionVille'), 'v.id_ville = rv.id_ville')
        ->join(array('r' => 'table2_region'), 'rv.id_region = r.id_region')
        ->where('r.nom_region like ?', 'Provence');
     
    return $this->table3_RegionVille->fetchAll($subSelect )->toArray();

    j'ai juste essayé ce code là pour commencer,
    avec table3_RegionVille->getAdapter()->select()
    il me renvoie
    Catchable fatal error: Object of class AnalyserController could not be converted to string in controller.php
    ey si je met avec table3_RegionVille->select()
    il renvoie:
    Exception : Zend_Db_Statement_Exception Message : SQLSTATE[42000]: Syntax error or access violation: 1065 Query was empty

    Si quelqu'un pourrait me dire pourquoi ma requête ne fonctionne pas, ça maiderait bcp


    Merci d'avance!

  14. #14
    Membre expert
    Bonjour,

    Citation Envoyé par benja507 Voir le message
    avec table3_RegionVille->getAdapter()->select()
    il me renvoie
    Catchable fatal error: Object of class AnalyserController could not be converted to string in controller.php
    Cette erreur parle d'un objet de classe "AnalyserController", et je ne vois pas le rapport avec la requête. En tous cas, il ne s'agit pas d'une classe du Framework à ma connaissance... Est-ce qu'il s'agit du classe que tu as créée ?


    Citation Envoyé par benja507 Voir le message
    Si quelqu'un pourrait me dire pourquoi ma requête ne fonctionne pas, ça maiderait bcp
    C'est ce que j'essaie de faire...

  15. #15
    Modérateur

    Je sais, je suis vieux jeu; mais ceci ne serais pas plus simple

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    $db = $this->getAdapter();
     
    $sql = "
     
    SELECT nom_ville 
    	FROM table1_ville v
    		INNER JOIN table3_RegionVille rv
    		ON v.id_ville = rv.id_ville
    			INNER JOIN table2_region r
    			ON rv.id_region = r.id_region
    WHERE r.nom_region LIKE 'Provence'
     
    ";
     
    return $this->db->fetchAll($sql);

  16. #16
    Membre expert
    Citation Envoyé par MaitrePylos Voir le message
    Je sais, je suis vieux jeu; mais ceci ne serais pas plus simple
    Plus simple, certainement (quoique je ne trouve pas que l'utilisation d'un Zend_Db_Select soit très compliquée).

    Mais il me semble que c'est moins paramétrable (ajouter une clause Where ou une jointure est vraiment très simple avec un Zend_Db_Select), moins lisible (avec un Zend_Db_Select, par exemple, les données à récupérer sont indiquées pour chaque table ajoutée, et pas en vrac dans la clause select), donc moins facile à maintenir (mais ça c'est peut-être subjectif), et en tous cas moins portable.

    Mais ce n'est que mon avis

  17. #17
    Candidat au Club
    controleur et vue d'une jointure à 3 tables
    Bonjour,
    s'il vous plaie quelqu'un me dit comment faire le controleur et l'affichage(vue) avec cette requête à 3 tables