Multiple ManytoMany et delete

L’auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Bonjour,

sous symfony 3.4.

j’ai une entity service liée en ManyToMany avec une entity agence
Une agence peut adhérer à plusieurs services et 1 service peut être adhérer par plusieurs agences.

J’ai aussi une entity user liée en ManyToMany avec l’entity service et en ManyToOne avec l’entity Agence. 1 User dépend d’une seule agence et il y a plusieurs users par agence.
1 User peut être attribué à plusieurs services et 1 services à plusieurs adhérants.

Enfin j’ai des plannings. 1 planning est lié en ManyToOne agence, ManyToONe service, il n’est pas lié à user.

Pour faire simple, j’ai créé une page pour les responsables d’agence, souhaitant souscrire/dé-souscrire à un service.

La question est, si un responsable dé-souscrit à un service pour son organisme, comment supprimer les liaisons avec user et planning de façon indolore?

Merci par avance :)

extrait de l’entity service

    /**
     * @ORM\OneToMany(targetEntity="Planning", mappedBy="service", cascade={"remove"})
     * @ORM\JoinColumn(onDelete="CASCADE", onUpdate="CASCADE") 
     */
    private $plannings;

    /**
    * @ORM\ManyToMany(targetEntity="AppBundle\Entity\User", mappedBy="services")
    * @ORM\JoinColumn(onDelete="CASCADE", onUpdate="CASCADE")
    */
    private $users;

    /**
    * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Agence", mappedBy="services")
    */
    private $agences;

extrait de user

/**
     * @ORM\ManyToOne(targetEntity="Agence", inversedBy="users")
     * @ORM\JoinColumn(nullable=false)
     */
    private $agence;

    /**
    * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Service")
    */
    private $services;

extrait d’agence

/**
     * @ORM\OneToMany(targetEntity="Planning", mappedBy="agence", cascade={"remove"})
     */
    private $plannings;

    /**
     * @ORM\OneToMany(targetEntity="User", mappedBy="agence", cascade={"remove"})
     */
    private $users;

    /**
    * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Service", inversedBy="agences", cascade={"persist"})
    */
    private $services;

extrait de planning

    /**
     * @var string
     * @ORM\ManyToOne(targetEntity="Service", inversedBy="plannings"))
     * @ORM\JoinColumn(nullable=false)
     */
    private $service;

    /**
     * @var string
     * @ORM\ManyToOne(targetEntity="Agence", inversedBy="plannings"))
     * @ORM\JoinColumn(nullable=false)
     */
    private $agence;

j’ai un palliatif, mais j’aurai souhaité gérer proprement depuis doctrine, c’est un peu barbare je trouve.

$services = $em->getRepository('AppBundle:Service')->findAll();

if(null != $request->request->get('service')){
    foreach($services as $s){
        if(!in_array($s->getId(), $request->request->get('service'))) {
            $plannings = $em->getRepository('AppBundle:Planning')->findby(array('service'=>$s, 'agence'=>$agence));
            foreach($plannings as $p){
                    $em->remove($p);
            }
            $users = $em->getRepository('AppBundle:User')->findby(array('agence'=>$agence));
            foreach($users as $u){
                     $u->removeService($s);
                     $em->persist($u);

            }
         }
     }            
     $em->flush();
}

Édité par Leeroy Jenkins

+0 -0

Salut !

J’essaie de réfléchir : est-ce que tu enregistres quelque part la date de début de la souscription au service par une agence ? Parce que si c’est le cas, vu qu’on aurait une entité intermédiaire qui apparaîtrait dans la ManyToMany, on peut imaginer un "soft delete" (proposé entre autres par gedmo/doctrine-extensions) avec un comportement de cascade sur les plannings. Et tu conserves la date de souscription et de désinscription, ce qui ne devrait pas gêner en cas de réinscription, d’ailleurs.

Evitez qu’on vous dise de les lire : FAQ PHP et SymfonyTutoriel WAMP • Cliquez 👍 pour dire merci • Marquez vos sujets résolus

+0 -0

Une autre possibilité à laquelle je pense maintenant serait d’utiliser un EntityListener pour permettre ce comportement de cascade. C’est probablement en partie ce qui est fait en cas de suppression en cascade réelle, donc…

Evitez qu’on vous dise de les lire : FAQ PHP et SymfonyTutoriel WAMP • Cliquez 👍 pour dire merci • Marquez vos sujets résolus

+0 -0

A ta place, j’aurai plus fait deux simples delete (DELETE FROM AppBundle:Planning p WHERE p.service = :service + et tout le des requetes préparées), bien que la deuxieme soit probablement un peu plus tendue. Soit comme l’a dit Ymox tu fais une entité intermédiaire, soit tu fais du sql à l’ancienne DELETE FROM UserServices WHERE service_id = :service, ce qui dépend du nom de la table générée. Je ne suis pas sur qu’on puisse faire du DQL ou autre pour ce genre de cas (sans entité intermédiaire).

Au passage, oublie les entity listeners. Surtout dans ce genre de cas, ça peut provoquer pas mal de bétises et comportements indéterminés (des cas ou faire une action n’a pas forçement de le trigger). Utilise plutot un event listener que tu trigger quand tu veux.

Quantiquement votre. Extension de tests d’API via Behat (PHP) : Behapi

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte