Précédent   Forum des professionnels en informatique > PHP > Bibliothèques et frameworks > symfony
symfony Forum d'entraide sur le framework PHP symfony. Avant de poster : cours symfony et FAQ symfony
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 28/07/2011, 16h18   #1
Invité de passage
 
Homme
Inscription : juillet 2011
Messages : 2
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France, Hérault (Languedoc Roussillon)

Informations forums :
Inscription : juillet 2011
Messages : 2
Points : 0
Points : 0
Par défaut [Doctrine] Error : Unknown relation alias - InnerJoin et relation n-n

Bonjour à tous,

J'essaie de traduire une requête SQL à base de Inner Join avec Doctrine mais j'ai invariablement une erreur.
Ma requête SQL fonctionne, mais pas sa transposition via Doctrine.

Pour être plus précis, voici le schéma qui m'a permis de générer la DB :

Code :
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
39
40
 
Diu:
  columns:
    nom_diu: { type: string(255), notnull: true }
    (...)
 
##################################################
 
Specialite:
  actAs:
    NestedSet:  
      hasManyRoots: true
      rootColumnName: root_id
  columns:
    nom_specialite:
      type: string(255)
      notnull: true
  relations:    #On définit ici la relation n-n entre la table des DIU et la table des Spéciliatés.
    Dius:       #On donne le nom de la relation, en utilisant le nom de la table liée au pluriel 
      foreignAlias: Specialites    #Alias optionnel correspondant à la table courante (nom au pluriel)
      class: Diu    #la classe (ie la table) qui est liée à Specialite
      refClass: DiuSpecialite  #Nom de la table intermédiaire
      local: specialite_id   #Référence à l'object courant (Specialite) avec le nom de la colonne le concernant dans DiuSpecialite
      foreign: diu_id  #Idem avec la table Diu
 
DiuSpecialite:  #Définition de la table intermédiaire
  columns:
    diu_id: { type: integer, primary: true }
    specialite_id: { type: integer, primary: true }
  relations:
    Diu:
      onDelete: cascade  #le paramètre cascade permet de supprimer les lignes concernant soit une specialite soit un diu si celui-ci est supprimé.
      local: diu_id    #local représente la colonne de la table DiuSpecialite
      foreign: id      #foreign prend ici le nom de la colonne dans la table Diu (afin que Doctrine puisse faire le lien entreles clés primaires)
      foreignAlias: DiuSpecialites
    Specialite:
      onDelete: cascade
      local: specialite_id
      foreign: id
      foreignAlias: DiuSpecialites
J'ai donc une table Diu, une table Specialite, et une table intermédiaire DiuSpecialite qui me sert de liaison dans ma relation n-n, un Diu pouvant recouvrir plusieurs spécialités, et une spécialité avoir plusieurs DIU.

Je cherche à récupérer tous les DIU d'une spécialité ; ma requête SQL est donc celle-ci :

Code :
1
2
3
4
5
6
7
 
SELECT * FROM diu d
INNER JOIN diu_specialite ds ON
ds.diu_id = d.id
INNER JOIN specialite s ON
ds.specialite_id = s.id
WHERE s.nom_specialite = 'Acupuncture'
Cette requête fonctionne comme attendue, j'obtiens bien les éléments recherchés.

En revanche j'ai plus de mal pour la traduction avec Doctrine... Voici ma requête :

Code :
1
2
3
4
5
6
7
8
 
$this->liste=Doctrine_Query::create()
                ->select('d.nom_diu')
                ->from('Diu d')
                ->innerJoin('DiuSpecialite ds ON ds.diu_id = d.id')
                ->innerJoin('Specialite s ON s.id = ds.specialite_id')
                ->where('s.nom_specialite = "Acupuncture"')
                ->execute();
Et j'ai alors le message d'erreur suivant :
500 | Internal Server Error | Doctrine_Table_Exception
Unknown relation alias

avec entre autres les détails suivants :
Code :
1
2
3
4
5
6
7
8
9
 
at ()
in SF_ROOT_DIR/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Relation/Parser.php line 237 ...
 
                    return $this->getRelation($alias, false);
                } else {
                    throw new Doctrine_Table_Exception('Unknown relation alias ' . $alias);
                }
            }
Je comprends donc qu'il y a un problème au niveau de la définition des relations et/ou de leur utilisation mais je vois pas bien lequel...

J'aurais donc plusieurs questions :
- Que dois-je changer dans ma requête Doctrine pour qu'elle fonctionne comme ma requête SQL ?
- Est-ce un bon moyen de procéder pour effectuer cette requête ou y a t-il un moyen plus simple/efficace de faire (compte-tenue de ma relation n-n entre les 2 tables avec une table intermédiaire) ?

Merci d'avance pour vos réponses
symfonyc est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 29/07/2011, 10h36   #2
Membre du Club
 
Homme
Analyse système
Inscription : mars 2011
Messages : 406
Détails du profil
Informations personnelles :
Sexe : Homme

Informations professionnelles :
Activité : Analyse système

Informations forums :
Inscription : mars 2011
Messages : 406
Points : 67
Points : 67
essaye de redéfinir les relation dans tes Class (le dossier lib/doctrine/Diu.class.php) + les autre class de relation :
par exemple :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
class Facture extends BaseFacture
{
public function setUp() {
    	$this->hasOne(
    		'Mission',
    		array(
    			'local' => 'mission_idmission',
    			'foreign' => 'idmission'
    		)
    	);
}
}
Code :
1
2
3
4
5
6
7
8
9
10
class Mission extends BaseMission
{
public function setUp() {
$this->hasMany(
    		'Facture',
    		array(
    			'local' => 'idmission',
    			'foreign' => 'mission_idmission'
    		)
    	);
la requette est :
Code :
1
2
3
4
5
6
7
8
 
    function data() {
        $q = Doctrine_Query::create()
                ->from('mission M')
                ->innerJoin('M.Facture ET')
                ->orderBy('M.idmission DESC');
        return $q->execute() ;
    }
et c'est pareil pour les autre relation.et tu vide le cache symfony cc
benhsaien est déconnecté   Envoyer un message privé Réponse avec citation 01
Vieux 29/07/2011, 13h19   #3
Invité de passage
 
Homme
Inscription : juillet 2011
Messages : 2
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France, Hérault (Languedoc Roussillon)

Informations forums :
Inscription : juillet 2011
Messages : 2
Points : 0
Points : 0
Merci pour ta réponse benhsaien.

Cependant je ne pense pas que cela change grand chose puisque toutes ces relations ont déjà été définies dans les classes du dossier lib/model/doctrine/base/, générées automatiquement à partir du schema.

Finalement en continuant mes recherches, je suis tombé sur ce post :
http://groups.google.com/group/doctr...17c25024?fwc=1, et j'ai donc adapté la requête DQL de la sorte :

Code :
1
2
3
4
5
6
 
$this->liste=Doctrine_Query::create()
                ->select('d.nom_diu')
                ->from('Diu d, d.DiuSpecialite ds, ds.Specialite s')
                ->where('s.nom_specialite = "Acupuncture"')
                ->execute();
et... ça marche!
La requête SQL correspondante effectuée est la suivante :

Code :
1
2
3
4
5
6
 
SELECT d.id AS d__id, d.nom_diu AS d__nom_diu 
FROM diu d 
LEFT JOIN diu_specialite d2 ON d.id = d2.diu_id 
LEFT JOIN specialite s ON d2.specialite_id = s.id 
WHERE (s.nom_specialite = "Acupuncture")
Donc ça correspond bien à la requête que je cherchais à faire.

Donc Doctrine effectue les jointures tout seul, sûrement en se basant sur les relations définies dans le schema. C'est donc beaucoup plus simple que ce que je pensais... même si ça semble un peu "magique"

Cependant quelqu'un saurait-il m'expliquer pourquoi ma traduction DQL de la requête SQL ne fonctionnait pas ?
Je me dis "si ça marche en SQL, a fortiori ça devrait marcher en DQL"...
symfonyc est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 29/07/2011, 23h39   #4
Modérateur
 
Avatar de Michel Rotta
 
Homme Michel Rotta
Responsable d'exploitation informatique
Inscription : septembre 2005
Messages : 4 913
Détails du profil
Informations personnelles :
Nom : Homme Michel Rotta
Âge : 49
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Responsable d'exploitation informatique
Secteur : Distribution

Informations forums :
Inscription : septembre 2005
Messages : 4 913
Points : 7 505
Points : 7 505
Ton schéma est presque bon, il ne faut en aucun cas aller modifier les relations générées dans les classes... très mauvaise idée.

Tu peux réécrire la relation de la table Specialiste en supprimant les paramètres : local et foreign qui ne sont pas utilisé dans le cas d'une refClasse.

En fait, ta requête en DQL est encore plus simple que ce que tu écris.
Code php :
1
2
3
4
5
6
$this->liste=Doctrine_Query::create()
                ->select('d.nom_diu')
                ->from('Diu d)
                ->innerJoin('d.specialistes s')
                ->where('s.nom_specialite = "Acupuncture"')
                ->execute();
Tu peux donc faire totalement abstraction de la table intermédiaire dans la requête DQL.

La méthode innerJoin() n'est pas le pendant exacte de la commande INNER JOIN du SQL. Sa syntaxe n'est donc pas équivalente. Ta deuxième écriture aurait pu coller dans des innerJoin().

Effectivement, Doctrine se sert de ta description du modèle, si non, pourquoi s’embêter à la faire ?

L'objectif du DQL est de permettre de simplifier l'écriture d'une requête, pas de singer le SQL, si non, le PDO suffirait amplement.
__________________
Si tu donnes un poisson à un homme, il mangera un jour. Si tu lui apprends à pêcher, il mangera toujours (Lao Tseu).
  • Pensez à valoriser les réponses pertinantes, cliquez sur le bouton vert +1 pour indiquer votre accord avec la solution proposée.
  • Pensez à utiliser la balise [code] pour afficher du code, elle est cachée sous le bouton [#] dans l'éditeur.
  • Une discussion est terminée ? Alors le bouton est votre ami !
Michel Rotta est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 14h00.


 
 
 
 
Partenaires

Hébergement Web