Académique Documents
Professionnel Documents
Culture Documents
◦ Sens de l'association:
▪ unidirectionnelle : une seule !
• ManyToOne
• ManyToMany
• OneToOne
▪ Bidirectionnelle : l’association et son inverse
• une ManyToOne et la OneToMany inverse
• deux ManyToMany
• deux OneToOne
• Le coté « owner » des associations bidirectionnelles :
problème compliqué …...à suivre
◦ tester http://localhost:8000/essai/test25
App\Entity\Ordinateur^ {#676
-id: 3
-ip: "192.168.7.02"
-numero: 702
-salle: App\Entity\Salle^ {#678
-id: 9
-batiment: "D"
-etage: 7
-numero: 71
}
}
▪ L’association s’est bien faite.
• Les cascades :
◦ Modifiez le fichier Entity/Ordinateur.php
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Salle", cascade={"persist"})
*/
private $salle;
◦ la persistance de l'entité Ordinateur est étendue en cascade à son entité
associée
▪ Écrivons un nouveau test du code qui avait généré une erreur de
persistance : … avec d'autres numéros d'ordinateur
public function test27() {
$em = $this->getDoctrine()->getManager();
$salle = new Salle;
$salle->setBatiment('B');
$salle->setEtage(0);
$salle->setNumero(1);
$ordi = new Ordinateur;
$ordi->setNumero(703);
$ordi->setIp('192.168.7.03');
$ordi->setSalle($salle);
$em->persist($ordi);
$em->flush();
dump($ordi);
return new Response('<html><body></body></html>');
}
▪ Exécutons http://localhost:8000/essai/test27 : la cascade de persistance
marche !
• Fin de l'expérience :
Enlevez le commentaire sur la ligne setSalle
dans la fonction addOrdinateur
• Pas de problème de lecture des données de la base via le coté non « owner » :
en clair, par l'appel à la méthode getOrdinateurs()
◦ notre code test :
public function test32() {
$em = $this->getDoctrine()->getManager();
$ordi = new Ordinateur;
$ordi->setNumero(805);
$ordi->setIp('192.168.8.05');
$em->persist($ordi);
$salle = new Salle ;
$salle->setBatiment('D');
$salle->setEtage(8);
$salle->setNumero(85);
$salle->addOrdinateur($ordi);
$em->persist($salle);
$ordi2 = new Ordinateur;
$ordi2->setNumero(806);
$ordi2->setIp('192.168.8.06');
$em->persist($ordi2);
$salle->addOrdinateur($ordi2);
$em->flush();
$id = $salle->getId();
$em->clear();
$salleTrouve = $em->getRepository(Salle::class)->find($id);
$result = "";
foreach($salleTrouve ->getOrdinateurs() as $ordi)
$result .= $ordi->getIp().' ';
$ordinateurs = $salleTrouve->getOrdinateurs();
dump($ordinateurs);
return new Response('<html><body>'.$result.'</body></html>');
}
◦ la méthode clear( ) de l'EntityManager supprime toute persistance
• la réponse http://localhost:8000/essai/test32
192.168.8.05 192.168.8.06
◦ ça marche !
Voici le dump :
Exercices 4.1
• Ajouter une entité Chef qui possède un nom
• Modifier l'entité resto de façon à avoir une association de resto vers chef :
• un resto aura un chef au plus
• un chef peut posséder plusieurs restos
• avec PhpMyAdmin, créer quelques chefs qui seront associés à des restos
• Ajouter une action ModifierResto qui permet de modifier un resto existant sur
le modèle de l’action d’ajout qui a été mis en place via l’exo 1.3.
Supprimer l'association entre entités
• supprimer l'association coté "owner" :
◦ la seule solution est de mettre
l'association à la valeur nulle, si le
champs est "nullable"
public function test33() {
$em = $this->getDoctrine()
->getManager();
$ordi = new Ordinateur;
$ordi->setNumero(807);
$ordi->setIp('192.168.8.07');
$em->persist($ordi);
$salle = new Salle ;
$salle->setBatiment('D');
$salle->setEtage(8);
$salle->setNumero(87);
$ordi->setSalle($salle);
$em->persist($salle);
$em->flush();
dump($ordi);
$ordi->setSalle(null);
$em->flush();
$ordi = $this->getDoctrine()->getManager()
->getRepository(Ordinateur::class)
->findOneByNumero(807);
dump($ordi);
return new Response('<html><body></body></html>');
}
▪ Exécutons
http://localhost:8000/essai/test33
Ça marche !
• supprimer l'association coté non-"owner" :
Pas de problème car le code de la fonction removeOrdinateur() opère la
suppression sur le coté "Owner"
public function removeOrdinateur(Ordinateur $ordinateur): self {
if ($this->ordinateurs->contains($ordinateur)) {
$this->ordinateurs->removeElement($ordinateur);
if ($ordinateur->getSalle() === $this) {
$ordinateur->setSalle(null);
...
Exercice 4.2
• Créer une fonction qui supprime un chef et tous ses restos s'il y a
• Ajouter cette nouvelle fonctionnalité dans le site
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use App\Entity\Ordinateur;
use App\Entity\Salle;
{% block body %}
<h2>ajouter un ordinateur</h2>
{{ form(monFormulaire) }}
{% endblock %}
◦ testez
http://localhost:8000/ajout_ordinateur
Ça marche ! vérifiez avec
PhpmyAdmin
• Expérience :
Commentez la fonction __toString() de l'entité Salle et re testez
• query_builder
◦ Restreignons ce choix aux salles de numéro inférieur à 10 :
ajoutons à OrdinateurType :
use App\Repository\SalleRepository;
...
->add('salle', EntityType::class,
array('class' => Salle::class,
'query_builder' => function (SalleRepository $repo) {
return $repo->createQueryBuilder('s')
->where('s.numero < 10'); }
));
...
◦ testez l’ajout d’ordinateur :
http://localhost:8000/ajout_ordinateur
Exercice 4.3 :
• Mettez à jour la page « ajouter un resto » de telle manière à ce que le champs chef
du formulaire corresponde à la liste des chefs (ordonnée selon les noms).
• Mettez à jour le reste de votre site de façon à prendre en compte le fait que le
champs chef de votre classe resto correspond dorénavant à une association et non
une chaîne de caractères.
many to many bidirectionnel :
/**
* @ORM\Entity(repositoryClass="App\Repository\LogicielRepository")
*/
class Logiciel {
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=25)
*/
private $nom;
/**
* @ORM\ManyToMany(targetEntity="App\Entity\Ordinateur",
* inversedBy="logiciel_installes", cascade={"persist"})
*/
private $machine_installees;
}
◦ et un "leftJoin" :
Ajoutons-le dans LogicielRepository.php :
public function getLogicielsEtEventuellementOrdinateurs() {
return $this->createQueryBuilder('l')
->select('l.nom', 'o.ip')
->leftjoin('l.machine_installees', 'o')
->getQuery()
->getResult();
}
▪ on sélectionne les logiciels installés sur des machines ou pas
◦ nouvelle action test42 :
public function test42() {
$em = $this->getDoctrine()->getManager();
$logicielC = new Logiciel ;
$logicielC->setNom('Apache');
$em->persist($logicielC);
$em->flush();
$repom = $em->getRepository(Logiciel::class);
$logicielOrdis = $repom->getLogicielsEtEventuellementOrdinateurs();
$result = ' ';
foreach ($logicielOrdis as $logicielOrdi)
$result .= $logicielOrdi['nom'].' : '.$logicielOrdi['ip'].'<br />';
return new Response('<html><body>'.$result.'</body></html>');
}
◦ tester http://localhost:8000/salle/essai/test42
Firefox : 192.168.10.01
Firefox : 192.168.10.00
Gimp2.2 : 192.168.10.01
Gimp2.2 : 192.168.10.00
Apache :
make:crud
• Générez un nouveau projet crudSalleTp
commencez par stopper l'actuel serveur
$ symfony server:stop
$ cd ..
$ symfony new --version=4.4 crudSalleTp
$ cd crudSalleTp
$ symfony server:start -d
/**
* @ORM\Entity(repositoryClass="App\Repository\OrdinateurRepository")
*/
class Ordinateur {
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=15)
*/
private $ip;
/**
* @ORM\Column(type="smallint", nullable=true)
*/
private $numero;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Salle", inversedBy="ordinateurs",
* cascade={"persist"})
*/
private $salle;
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=1)
*/
private $batiment;
/**
* @ORM\Column(type="smallint")
*/
private $etage;
/**
* @ORM\Column(type="smallint")
*/
private $numero;
/**
* @ORM\OneToMany(targetEntity="App\Entity\Ordinateur", mappedBy="salle",
* cascade={"persist"})
*/
private $ordinateurs;
Générez tout le code réalisant les opérations CRUD sur les 2 entités :
$ symfony console make:crud Salle
created: src/Controller/SalleController.php
created: src/Form/SalleType.php
created: templates/salle/_delete_form.html.twig
created: templates/salle/_form.html.twig
created: templates/salle/edit.html.twig
created: templates/salle/index.html.twig
created: templates/salle/new.html.twig
created: templates/salle/show.html.twig
Success !
◦ Testez : http://localhost:8000/salle/
▪ Allez voir le code des contrôleurs,
templates, forms, ...
Exercices 4.5