[RESOLU] tableau objet

dooki
Invité n'ayant pas de compte PHPfrance

18 févr. 2020, 17:29

Bonjour voici mon petit problème :

J'ai une fonction

Code : Tout sélectionner

private function getNumMedecins($numero){ $numero = ($_GET['num']); $numDep = ""; $em = $this->getDoctrine()->getManager()->getRepository('App:Medecin'); $searchMed = $em->findBy(['departement'=>$numero]); $searchAll = $em->findAll(); $eme = $this->getDoctrine()->getManager()->getRepository('App:Dep'); $searchDep = $eme->findAll(['num'=>$numDep]); $numDep = $searchDep;
$searchMed me ramene tout les departement des medecins dans la variable $numero dans un array
$searchAll me ramene tout les colonnes de la table Medecin dans u n array
et $SearchDep toutes les colonnes de la table Dep dans variable $numDep

J'aimerais afficher uniquement les medecins qui possède le departement (exemple 04 ), avec le departement correspondant ds la table Dep..

J'aimerais faire quelque chose qui ressemble à :
if $searchAll.$numero = $_GET['numDepp'] {echo 'Liste des medecins'}

J'ai tenté un
(foreach medecin as medecins )
<?php if ($numDep = $numero){ ?>
medecin.nom

Mais ca ne fonctionne pas

Avatar du membre
Mammouth du PHP | 1609 Messages

18 févr. 2020, 17:56

Salut, une égalité ça ce teste avec un == et non un = qui est un opérateur d'affectation.

Sinon les médecins qui ont le bon département sont sensés être dans $searchMed puisque tu fais un findBy(['departement' => $numero])
Développeur web depuis + de 20 ans

dooki
Invité n'ayant pas de compte PHPfrance

18 févr. 2020, 19:32

Salut, une égalité ça ce teste avec un == et non un = qui est un opérateur d'affectation.
Oui, pardon c'est ce que j 'avais fait.
Sinon les médecins qui ont le bon département sont sensés être dans $searchMed puisque tu fais un findBy(['departement' => $numero])
Je l'avais changer car je recevais : Variable "searchMed" does not exist.
quand je le met dans le IF !!

Même en ajoutant un return $searchMed dans la fonction , rien n'y fait

dooki
Invité n'ayant pas de compte PHPfrance

18 févr. 2020, 19:54

Tu as raison le problème vient trés certainement de cette ligne
$searchMed = $em->findBy(['departement'=>$numero]);
private function getNumMedecins($numero){
$numero = ($_GET['num']);
$numDep = "";
$em = $this->getDoctrine()->getManager()->getRepository('App:Medecin');
$searchMed = $em->findBy(['departement'=>$numero]);
$searchAll = $em->findAll();
$eme = $this->getDoctrine()->getManager()->getRepository('App:Dep');
$searchDep = $eme->findAll(['num'=>$numDep]);

if ($numero == 3 ){echo "<script>alert('test');</script>";}
Le script alert marche si num=3 dans ma barre d'adresse mais si je remplace le 3 par searchMed, cela ne marche plus ,
un var_dump($searchMed); renvoie pourtant bien un tableau , avec beaucoup( trop?) d'informations pourtant !

Avatar du membre
Mammouth du PHP | 1609 Messages

18 févr. 2020, 20:01

En fait si tu veux une méthode qui prend le numéro de département en paramètre et retournes les médecins et le département, tu peux faire comme ça (en admettant que la propriété departement de l'entité Medecin contienne bien le numéro de département) :
  private function getMedecinsAndDepartementByNumeroDepartement($numero)
  {
    $manager = $this->getDoctrine()->getManager();

    return [
      'medecins' => $manager->getRepository('App:Medecin')->findBy(['departement' => $numero]),
      'departement' => $manager->getRepository('App:Dep')->findOneBy(['num' => $numero])
    ];
  }

Le findBy va te retourner un tableau de médecins filtrés par département et findOneBy va te retourner le premier département filtré par département.

Tu peux utiliser la méthode comme ceci (depuis une méthode fictive de la même class) :
  public function randomMethod() {
    extract($this->getMedecinsAndDepartementByNumeroDepartement('04'));

    // boucle sur les médecins
    foreach ($medecins as $medecin) { 
      /*...*/
    }

    // accès à la propriété num du département
    $departement->getNum();
  }

PS : en admettant que tu ais une liaison standard entre médecins et départements (genre propriété departement de l'entité Medecin en OneToMany vers l'entité Dep) le code devrait plutôt ressembler à ça :
  private function getMedecinsAndDepartementByNumeroDepartement($numero)
  {
    $manager = $this->getDoctrine()->getManager();

    $departement = $manager->getRepository('App:Dep')->findOneBy(['num' => $numero]);

    $medecins = $departement
      ? $manager->getRepository('App:Medecin')->findBy(['departement' => $departement])
      : [];

    return [
      'medecins' => $medecins,
      'departement' => $departement
    ];
  }

Et y aurait encore quelques autres manières d'écrire tout ça.
Développeur web depuis + de 20 ans

dooki
Invité n'ayant pas de compte PHPfrance

18 févr. 2020, 21:40

Merci beaucoup pour le temps que tu as pris,cela me parait pas mal (et bien expliquer) et en total cohérence avec ma demande, j'essaie ça au plus vite !!

Avatar du membre
Mammouth du PHP | 1609 Messages

18 févr. 2020, 22:10

Je crois que je me suis trompé sur la relation qui devrait plutôt être ManyToOne. Dans Medecin, $departement en ManyToOne et dans Dep, $medecins en OneToMany.
Développeur web depuis + de 20 ans

dooki
Invité n'ayant pas de compte PHPfrance

19 févr. 2020, 00:46

J'ai essayé :

Code : Tout sélectionner

public function randomMethod() { extract($this->getMedecinsAndDepartementByNumeroDepartement('04')); }
avec la boucle , dans ma vue :

Code : Tout sélectionner

foreach ($medecins as $medecin) { /*...*/
}
La function qui fait appel à l'autre méthode " getMedecinsAndDepartementByNumeroDepartement "
renvoie encore la totalité des médecins malgrés le paramètre placé entre parenthèses .. je commence à me demander si j'ai pas fais une bourde dans le passage des variables ..

Dans mon Controlleur pour ma page home :

Code : Tout sélectionner

public function home(){ $num =""; if (isset($_GET['recherche'])) { $nom = ($_GET['recherche']); }else { $nom =""; } if (isset($_GET['{{dept}}'])) { $nom = ($_GET['nom']); }else { $nom =""; } if (isset($_GET['num'])) { $numero = ($_GET['num']); }else { $numero =""; } if (isset($_GET['recherche'])) { $nom = ($_GET['recherche']); }else { $nom = ""; } return $this->render ('medecin/home.html.twig', ['title' => "Bienvenue sur le site", 'liste' => "Voici la liste des medecins✅", 'dept' => $this->getDept(), 'medecins' => $this->getMedecins(), 'recup' => $this->recup(), 'numero' => ($_GET['num']), 'nom' => $nom, 'dept'=> $this->getDept($nom), 'lesDept' => $this->lesDepsNom($num), 'meds' => $meds ]);

dooki
Invité n'ayant pas de compte PHPfrance

19 févr. 2020, 00:54

J'ai remplacé :

Code : Tout sélectionner

'medecins' => $this->getMedecins(),
par
'medecins' => $this->recup(),
public function recup() {
extract($this->getMedecinsAndDepartementByNumeroDepartement('1'));


}
Toujours pas :'(

Avatar du membre
Mammouth du PHP | 1609 Messages

19 févr. 2020, 11:39

Si tu fais pas un return à la fin de la méthode recup() forcément ça ne retourne rien...
public function recup() {
  extract($this->getMedecinsAndDepartementByNumeroDepartement('1'));
  return $medecins;
}

Y a tellement de choses qui vont pas dans ton code que ça en est un peu compliqué de t'aider.

Dans ta dernière méthode home() :
  public function home()
  {
    $num = "";// définie vide puis jamais affectée

    if (isset($_GET['recherche'])) {
      $nom = ($_GET['recherche']);
    } else {
      $nom = "";
    }

    if (isset($_GET['{{dept}}'])) {// tu as vraiment un input name="{{dept}}" ??? de plus tu testes isset get {{dept}} mais tu affectes get nom...
      $nom = ($_GET['nom']);
    } else {
      $nom = "";
    }
    
    // $nom vient de get recherche ou get nom ???

    if (isset($_GET['num'])) {
      $numero = ($_GET['num']);
    } else {
      $numero = "";
    }
    
    // $numero n'est jamais utilisé

    // et hop on se refait un petit coup de get recherche déjà au début...
    if (isset($_GET['recherche'])) {
      $nom = ($_GET['recherche']);
    } else {
      $nom = "";
    }

    // la valeur $nom me semble assez incertaine... mais bon apparemment elle ne sert pas à grand chose puisqu'elle est juste transmise à la vue. Un {{ app.request.query.get('nom') }} dans twig pourrait faire l'affaire sans s'embêter dans le contrôleur.
    // à non en fait c'est bien utilisé avec $this->getDept($nom) mais du coup la valeur est-elle bonne ?

    return $this->render('medecin/home.html.twig', [
      'title' => "Bienvenue sur le site",
      'liste' => "Voici la liste des medecins✅",
      'dept' => $this->getDept(),
      'medecins' => $this->getMedecins(),
      'recup' => $this->recup(),
      'numero' => ($_GET['num']),// et si get num n'existe pas ???
      'nom' => $nom,
      'dept' => $this->getDept($nom),// y a déjà un dept au dessus... et puis t'es sur qu'il y a ce qu'il faut dans $nom ? et que getDept prend bien en compte le paramètre et retourne bien quelque chose ???
      'lesDept' => $this->lesDepsNom($num),// $num est vide...
      'meds' => $meds// $meds c'est quoi ça sort d'où ???
    ]);
  }

Alors bon déjà essaie de nettoyer ton code, enlève tout ce qui ne sert à rien. Vérifie bien que les paramètres sont bien fournis et que tu as bien les retours qu'il faut sur les différentes méthodes et après on pourra voir peut être s'il y a encore des problèmes.

En restant simple, tu sembles faire du symfony, tu devrais donc avoir quelque chose comme le code ci-dessous. Ce n'est qu'un exemple ne sachant pas précisément ce que tu veux faire. C'est donc à adapter selon tes besoins spécifiques, mais à priori tu as la base pour faire ce que tu veux.
  public function home(Request $request)
  {
    // le numéro de département est-il transmis dans la requête ?
    if ($request->query->has('num')) {
      // on récupère le département via son numéro
      $departement = $this->getDoctrine()->getRepository(Dep::class)
        ->findOneBy([
          'num' => $request->query->get('num')
        ]);

      // si le département existe récupère les médecins du département
      if ($departement)
        $medecins = $this->getDoctrine()->getRepository(Medecin::class)
          ->findBy([
            'departement' => $departement
          ]);

      // si les relations sont biens définies dans les entités, pour récupérer les médecins du département il suffirait de faire
      if ($departement)
        $medecins = $departement->getMedecins();
    }

    // si $medecins n'est pas définie, initialise avec tous les médecins
    if (!isset($medecins))
      $medecins = $this->getDoctrine()->getRepository(Medecin::class)
        ->findAll();

    return $this->render('medecin/home.html.twig', [
      'departements' => $this->getDoctrine()->getRepository(Dep::class)->findAll(),
      'departement' => $departement,// peut être null donc tester avant d'utiliser, dans twig {% if departement %}
      'medecins' => $medecins,
    ]);
  }

Et donc en simplifié tu pourrais avoir :
  public function home(Request $request)
  {
    $departement = $request->query->has('num') 
      ? $this->getDoctrine()->getRepository(Dep::class)
        ->findOneBy([
          'num' => $request->query->get('num')
        ])
      : null;
    
    $medecins = $departement
      ? $departement->getMedecins()
      : $this->getDoctrine()->getRepository(Medecin::class)
        ->findAll();
    
    return $this->render('medecin/home.html.twig', [
      'departements' => $this->getDoctrine()->getRepository(Dep::class)->findAll(),
      'departement' => $departement,
      'medecins' => $medecins,
    ]);

Pour compléter ci-dessous ce que devrait être les propriétés departement et medecins :
  // dans App\Entity\Medecin
  /**
   * @ORM\ManyToOne(targetEntity="App\Entity\Dep", inversedBy="medecins")
   * @ORM\JoinColumn(nullable=false)
   */
  private $departement;

  // dans App\Entity\Dep
  /**
   * @ORM\OneToMany(targetEntity="App\Entity\Medecin", mappedBy="departement", orphanRemoval=true)
   */
  private $medecins;
Développeur web depuis + de 20 ans

dooki
Invité n'ayant pas de compte PHPfrance

19 févr. 2020, 15:40

Merci encore pour le temps que tu prends pour mon cas !

Je suis encore débutant sur symfony ( comme tu as pu le remarquer )
Aprés plusieurs tentatives , j'ai reçu un message d'erreur,
Return value of App\Entity\Medecin::getDepartement() must be of the type integer or null, object returned
=> La colomne departement de la table medecin a été remplacé par departement_id surement causé par :

Code : Tout sélectionner

/** * @ORM\ManyToOne(targetEntity="App\Entity\Dep", inversedBy="medecins") * @ORM\JoinColumn(nullable=false) */ $private departement

et les setters et getters sont née aprés une migration :

Code : Tout sélectionner

public function getDepartement(): ?int { return $this->departement; // Apparement ce département retourne un objet alors que la variable $departement } public function setDepartement(int $departement): self { $this->departement = $departement; return $this; }
pourtant le $departement retourne bien un num de département ?

Code : Tout sélectionner

$departement = $request->query->has('num') ? $this->getDoctrine()->getRepository(Dep::class) ->findOneBy([ 'num' => $request->query->get('num') ]) : null;

Avatar du membre
Mammouth du PHP | 1609 Messages

19 févr. 2020, 15:49

Les getter et setter n'ont pas été mis à jour car déjà présent. Logiquement ils devraient être comme ça (Dep et non int) :
    public function getDepartement(): Dep
    {
        return $this->departement;
    }

    public function setDepartement(Dep $departement): self
    {
        $this->departement = $departement;

        return $this;
    }

La l'erreur dit que ce devrait être de type integer ou null car le retour déclaré sur la méthode getDepartement est : ?int
Si tu as /*...*/getDepartement(): int tu dis que le retour doit être un integer
Si tu as /*...*/getDepartement(): ?int tu dis que le retour doit être un integer ou null

Ici le retour est bien sensé être un objet Dep donc /*...*/getDepartement(): Dep
La colonne étant délcarée en @ORM\JoinColumn(nullable=false) alors le département est obligatoire et il n'y a donc pas de ? car pas de valeur null autorisée.

=> La colonne departement de la table medecin a été remplacé par departement_id surement causé par :
Normale, effectivement tu avais du la déclarer en integer auparavant. Maintenant qu'elle est liée à l'entité Dep c'est bien une clé étrangère departement_id qui pointe vers l'id du département (et non le numéro du département).

Du coup depuis un médecin tu peux accéder au département et à ses propriétés :
$medecin->getDepartement()->getNum();

PS : si tu veux pouvoir enregistrer un médecin sans définir son département alors JoinColumn doit être défini en nullable=true et dans ce cas tu peux mettre sur le retour du getter ?Dep et sur le paramètre du setter ?Dep.

PPS : je ne sais pas si tu es sur un nouveau projet ou si tu repars d'une BDD existante.

Dans le premier cas je pense que tu as tout intérêt à bien faire la BDD avec une vraie liaison de tables.

Mais dans le deuxième cas si tu as une BDD bien fournie et que les départements sur les médecins sont enregistrés via leur numéro de département, peut être que tu devrais rester sur une colonne integer et écrire le code en fonction.
Dans ce cas mon code est partiellement erroné.

A moins que miraculeusement les id des départements correspondent aux numéros des départements, dans ce cas tu pourrais faire la bascule vers une vraie liaison.
Développeur web depuis + de 20 ans

dooki
Invité n'ayant pas de compte PHPfrance

19 févr. 2020, 16:47

J'en apprends beaucoup plus en lisant tes conseils que sur la plupart des vidéos/tuto internet !
Du coup depuis un médecin tu peux accéder au département et à ses propriétés :

$medecin->getDepartement()->getNum();
Le problème c'est que ma vue est en .Twig et que même en ajoutant des balises PHP, cela affiche :getDepartement()->getNum();
comme si il y'avait un echo ..

J'ai tenté dans le controleur mais il ne connait pas medecin vu que la var medecin est créer dans la boucle for de la vue twig

PPS : je ne sais pas si tu es sur un nouveau projet ou si tu repars d'une BDD existante.
J'ai juste une table :
CREATE TABLE IF NOT EXISTS medecin (
id int(11) NOT NULL AUTO_INCREMENT,
nom varchar(30) NOT NULL,
prenom varchar(30) NOT NULL,
adresse varchar(80) NOT NULL,
tel varchar(15) DEFAULT NULL,
specialiteComplementaire varchar(50) DEFAULT NULL,
departement int(11) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=7 ;
ainsi que des centaines de lignes de coordonnées de medecin :
insert into medecin(nom,prenom,adresse,tel,specialitecomplementaire,departement) values('Ségura','John','3 rue de la Tour FRESSANCOURT 02800','0331446881',NULL,02);
A moins que miraculeusement les id des départements correspondent aux numéros des départements, dans ce cas tu pourrais faire la bascule vers une vraie liaison.
C'est effectivement comme ça que je l'ai créer héhé, qu'appelles tu une vraie liaison ?

Sais tu si il y'a une méthode pour lire les departements des médecins sur les vues twig ?
avant j'y accédais par un {{ medecin.departement }}
$medecin->getDepartement()->getNum();
J'aimerais mettre celle la dans une $var pour pouvoir l'appeller dans ma boucle ( possible ? )

Pour l'instant il à toujours l'air de me renvoyer tout les médecins de tout les départements..
Je nage un peu dans la semoule depuis le php orienté objet pourtant ça à pas l'air méchant !!

Avatar du membre
Mammouth du PHP | 1609 Messages

19 févr. 2020, 17:02

Pour la ligne php dans twig c'est pas sorcier :
$medecin->getDepartement()->getNum();
// devient
{{ medecin.departement.num }}

Pour la table, tu devrais plutôt avoir departement_id int(11) NOT NULL, ou la valeur est l'id du département correspondant dans la table des départements. Avec la clé étrangère bien définie. Normalement avec le make:migration ça devrait le faire tout seul mais il faudrait que tu alimentes la colonne comme il faut pour chaque médecin.

C'est ce que j'appelle une vraie liaison. Tu lies les tables via les id et non pas via une valeur d'une colonne particulière. C'est comme ça qu'on gère normalement les relations entre tables dans une base de données.

Vraie liaison avec clé étrangère (many medecins to one departement, one departement to many medecins) :
medecin
- id
- nom
- prenom
- departement_id (clé étrangère faisant référence à departement.id)

departement
- id
- nom
- numero
Fausse liaison :
medecin
- id
- nom
- prenom
- numero_departement (numéro du département pas de référence)

departement
- id
- nom
- numero
Avec la vraie liaison tu as des syntaxes qui n'existent pas sans :
$medecin->getDepartement()->getNom();// twig {{ medecin.departement.nom }}
$medecin->getDepartement()->getNumero();// twig {{ medecin.departement.numero }}
$departement->getMedecins();// twig {{ departement.medecins }}

Mais la manière de récupérer les données diffère.
Récupérer les médecins d'un département avec vraie liaison :
$medecins = $this->getDoctrine()->getRepository(Medecin::class)->findBy([
  'departement' => $departement // avec $departement étant l'entité du département en question qu'il faut donc avoir récupéré au préalable
]);

// mais si tu veux directement récupérer les médecins via le numéro de département sans récupérer le département avant tu peux aussi écrire
$medecins = $this->getDoctrine()->getRepository(Medecin::class)->createQueryBuilder('m')
  ->join('departement', 'd')
  ->where('d.numero = :numero')
  ->setParameters([
    'numero' => $numero // avec $numero égal au numéro de département
  ])->getQuery()->getResult();

// ou tu peux récupérer le département puis les médecins
$departement = $this->getDoctrine()->getRepository(Departement::class)->findOneBy([
  'numero' => $numero // avec $numero égal au numéro de département
]);
$medecins = $departement->getMedecins();

Avec la fausse liaison tu ferais un :
$medecins = $this->getDoctrine()->getRepository(Medecin::class)->findBy([
  'numeroDepartement' => $numero // avec $numero égal au numéro de département
]);
Mais tu n'as pas de getDepartement() sur les médecins et tu n'as pas de getMedecins() sur les départements.
Modifié en dernier par Saian le 19 févr. 2020, 18:13, modifié 1 fois.
Développeur web depuis + de 20 ans

dooki
Invité n'ayant pas de compte PHPfrance

19 févr. 2020, 17:52

Je prends note et quelques captures d'écran et je relirais tout ca dans mon cours pour être sur de tout comprendre !

Une dernière petite question :
Pour afficher uniquement les medecins du département 1 , en cliquand sur le lien j'arrive sur :
le $_GET n'est pas forcement nécessaire ??
le " $request->query->has('num') " est surement mieux ?

Serait t'il possible de faire quelque chose dans le même style :(dans le controleur)

Code : Tout sélectionner

$medecins = $this->getDoctrine()->getRepository(Medecin::class) ->findAll($departement['num']);
C'est à dire prendre tout les Medecins ou le departement = num (=1 dans la barre d'adresse' )