Partage
  • Partager sur Facebook
  • Partager sur Twitter

Vérifier qu'un utilisateur est inscrit Symfony

Sujet résolu
27 octobre 2021 à 8:43:20

Bonjour à tous,

Je rencontre un problème avec Symfony : j'aimerais vérifier qu'un utilisateur est inscrit ou non à un évènement.

Voici le contexte : j'ai une entité User, une entité Event et une entité SubscriptionEvent. La première est une entité User classique de Symfony, la seconde est une entité qui accueille tous les évènements que je veux (c'est un site évenementiel en gros) et la troisième accueille donc un User ainsi qu'un Event lorsque l'User s'inscrit.

Ici l'entité SubscriptionEvent :

/**
 * @ORM\Entity(repositoryClass=SubscriptionEventRepository::class)
 *
 * @UniqueEntity(fields={"event","user"}, message="Votre inscription a déjà été enregistrée")
 */
class SubscriptionEvent
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity=Events::class, inversedBy="subscriptionEvents")
     */
    private $event;

    /**
     * @ORM\ManyToOne(targetEntity=User::class, inversedBy="subscriptionEvents")
     */
    private $user;

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getEvent(): ?Events
    {
        return $this->event;
    }

    public function setEvent(?Events $event): self
    {
        $this->event = $event;

        return $this;
    }

    public function getUser(): ?User
    {
        return $this->user;
    }

    public function setUser(?User $user): self
    {
        $this->user = $user;

        return $this;
    }
}

J'ai une page qui liste mes évènements et on peut s'inscrire sur chacun de ces évènements. J'aimerai donc que, si la personne est déjà inscrite, mettre un texte "déjà inscrit" par exemple.

La route dans mon controller :

  #[Route('/', name: 'events_index', methods: ['GET'])]
    public function events(EventsRepository $eventsRepository, SubscriptionEventRepository $subscriptionEventRepository): Response
    {
        $subscriptions = $subscriptionEventRepository->findBy(['user' => $this->getUser()]);
        $events = $eventsRepository->findAll();


        return $this->render("events/index.html.twig", [
            "events" => $events,
            "subscriptions" => $subscriptions
        ]);
    }

Pour l'instant, cela n'a pas tellement d'intérêt la variable "subscriptions" puisque je ne l'utilise pas dans ma vue.

Mais dans l'idée, j'aimerais donc pouvoir regarder ce que j'ai dans "subscriptions" et voir si l'event est dedans. Et si il ne l'est pas, j'affiche "s'inscrire" et si il y ait, c'est que la personne est déjà inscrite...

J'espère que ma question est a peu près clair... Sinon j'ajouterais des infos supplémentaires si besoin.

Merci à tous de votre aide.


  • Partager sur Facebook
  • Partager sur Twitter
27 octobre 2021 à 9:38:57

Bonjour,

Je n'ai peut-être pas bien compris mais dans ta vue qui part de event il suffit de tester si la relation avec user existe ou pas : si oui mention "déjà inscrit" si non possibilité de s'inscrire.

A+

-
Edité par monkey3d 27 octobre 2021 à 9:44:56

  • Partager sur Facebook
  • Partager sur Twitter
28 octobre 2021 à 17:05:24

Bonjour et merci pour cette réponse,

C'est exactement ce que je cherche à faire oui.

Mais comment faire ce test justement ? et à quel endroit ?

Merci

  • Partager sur Facebook
  • Partager sur Twitter
16 novembre 2021 à 19:16:16

Bonjour,

Bon je suis désolée, mais je ne vois pas comment faire.

Je précise que mes données sont comme ceci (peut être que ce sera plus facile pour m'aider) :

Et la vue  pour le moment :

{% extends 'base.html.twig' %}

{% block title %}Events{% endblock %}

{% block body %}
    <h1 class="mt-3 mb-3">{{ event.title }}</h1>

    {% if is_granted('ROLE_ADMIN') %}

        <a href="{{ path('events_edit', {'id': event.id}) }}" class="btn btn-secondary">Editer</a>

        {{ include('events/_delete_form.html.twig') }}
    {% endif %}

    <h2 class="mt-3 mb-3 text-muted">{{ event.subtitle }}</h2>
    <p class="text-muted"><i class="fa fa-location-arrow"></i> {{ event.place }}
        <br><i class="fa fa-clock-o"></i> {{ event.dateEvent|date('d/m/y') }}</p>

    <div class="card border-secondary mb-3" >
        <div class="card-body">
            {{ event.content|raw }}
        </div>
    </div>



    <p class="text-muted mt-3">Date limite d'inscription :  {{ event.dateDead|date('d/m/y') }}</p>
    {% if not is_granted('ROLE_ADMIN') and event.dateDead|date("Y-m-d") > "today"|date("Y-m-d") %}
        <a href="{{ path('subscription_eventuser_new', {'id': event.id}) }}" class="btn btn-primary">S'inscrire</a>
    {% endif %}


    <p class="mt-3"> <a href="{{ path('events_index') }}">Retour à la liste des évènements</a></p>

{% endblock %}


Merci beaucoup de votre aide

  • Partager sur Facebook
  • Partager sur Twitter
16 novembre 2021 à 19:58:48

Salut

Est-ce qu'il y a une raison pour que SubscriptionEvent soit une entité ? D'après ce que tu nous montres, elle ne contient que les deux colonnes de liaison en plus de l'ID.
Dit autrement : qu'est-ce qui fait qu'on a là une "One(User)ToMany(SubscriptionEvent)ToOne(Event)" ? Une Many(User)ToMany(Event) n'est pas possible ?

Auquel cas, après modification, il pourrait suffire de faire un test dans le genre de user.events.contains(event), ou l'inverse pourrait être un peu plus performant selon le nombre d'inscriptions possibles (event.users.contains(user)).

Si tu ne peux pas changer ta modélisation, alors il faut tester si l'utilisateur possède une inscription pour cet événement, quelque chose comme user.subscriptions.concerns(event) avec une méthode concerns dans l'inscription qui va filtrer pour ne conserver que celle qui concerne l'événement passé en paramètre (attention, on va comparer des IDs d'événements techniquement, pas les objets entre eux). Regarde en ce sens la documentation des collections de Doctrine.

  • Partager sur Facebook
  • Partager sur Twitter
18 novembre 2021 à 11:47:41

Salut,

Merci pour cette réponse. Du coup j'ai opté pour la première idée en changeant la modélisation. Cela fonctionne bien par contre je suis obligée de modifier des choses pour ajouter une inscription par exemple.

Donc, suite aux modifs, j'ai bien une table "events_user" qui possède deux colonnes avec l'ID event et l'ID user. Jusque là c'est ok. Par contre, dans mon inscription, je veux que la personne puisse ajouter un nombre de personnes total. Il peut venir avec quelqu'un. Donc il faudrait que je puisse ajouter une colonne "nombre de personnes" par exemple à la table events_user non ? Comment je peux faire cela puisque ce n'est pas une entité ?

Merci

  • Partager sur Facebook
  • Partager sur Twitter
18 novembre 2021 à 11:52:17

C'est exactement la question que je te posais dès le début du message, quand je demandais la raison d'avoir une entité entre celles des utilisateurs et celle des événements, il aurait été intéressant d'y répondre avant de changer la relation, vu qu'effectivement le changement ne permet plus d'avoir ces informations supplémentaires…

Et du coup c'est le dernier paragraphe du message précédent qui est plus pertinent.

  • Partager sur Facebook
  • Partager sur Twitter
18 novembre 2021 à 11:55:50

Ah ah ! Ouais je m'en suis un peu doutée lorsque j'ai répondu tout à l'heure...

En fait, au moment de ton premier message où tu posais cette question, il n'y avait pas cette histoire de nombre de personnes supplémentaires... C'est pourquoi j'étais partie sur l'option 1.

Mais bon, vu que cela s'est ajouté entre temps... me voilà repartie en arrière avec l'option 2.

Je reposterai en fonction du résultat !

EDIT :

Du coup, petite question

Il faut donc que je fasse une nouvelle méthode pour pouvoir filter et ne conserver que les inscriptions qui concernent l'évènement que je lui passe c'est bien cela ? Comment je fais pour la construire cette méthode ?

Cette méthode je la mets dans mon entité SubscriptionEvents ? Je suis désolée, mais je n'arrive pas trop à visualiser exactement comment faire pour le moment...

-
Edité par zazzou 18 novembre 2021 à 16:42:49

  • Partager sur Facebook
  • Partager sur Twitter
23 novembre 2021 à 14:50:33

Bonjour !

Je reviens par rapport à cette question car je n'arrive pas à voir comment fiare la nouvelle méthode et l'appeler ensuite.. J'aurais besoin d'un peu d'aide...

Merci à vous

  • Partager sur Facebook
  • Partager sur Twitter
23 novembre 2021 à 17:02:10

Je mettrais la méthode de vérification dans l'une des deux entités Events ou User, partant du principe qu'une personne va s'inscrire à plus d'événements qu'un événement peut recevoir de personnes, je mettrais dans Events.

Pour ce qui est de ce que doit faire la méthode, il suffit de prendre la liste des SubscriptionEvent et de vérifier si l'une d'entre elle concerne l'utilisateur courant dans le cas de méthode dans Event, ou l'événement dans le cas de méthode dans User.

-
Edité par Ymox 23 novembre 2021 à 17:02:24

  • Partager sur Facebook
  • Partager sur Twitter
30 novembre 2021 à 14:17:31

Bonjour

Bon j'ai beau essayer dans tous les sens, je ne m'en sors pas. J'ai opté pour l'ajout dans Events mais en dehors de faire $this->getSubscriptionEvents, je n'arrive pa à voir comment faire pour ensuite filtrer, ni pour appeler la méthode ensuite dans ma vue afin de mettre "s'inscrire" si il ne l'est pas et rien si il l'est...

Merci beaucoup pour ton aide

  • Partager sur Facebook
  • Partager sur Twitter
30 novembre 2021 à 21:58:37

Il y a une chose dont il faut se rendre compte : avec Twig, faire truc.chose, ça revient plus ou moins à faire en PHP $truc->getChose(), donc il s'agit d'un appel de fonction, ici on supposera que getChose() est l'accesseur de l'attribut $chose. Quand cet attribut est impliqué dans une relation *ToMany, ce qui est retourné est une collection, disons pour simplifier un tableau PHP. Il me paraît relativement simple de parcourir un tableau pour voir si un de ses éléments respecte une certaine contrainte. Par contre, attention : si c'est bien dans la vue qu'on va avoir besoin de savoir si un utilisateur est inscrit ou non à un événement, la logique de vérification ne devrait à mon avis pas être dans la vue. Le plus simple serait selon moi (et comme dit précédemment) de la mettre dans l'entité Events.

Pour le cas qui nous occupe, on a donc la propriété Events::subscriptionEvents qui nous retourne un tableau d'objets SubscriptionEvents. Pourquoi ne pas boucler sur les éléments de cette collection et de regarder si l'un d'entre eux concerne l'utilisateur courant, soit, pour être concret, si l'utilisateur enregistré dans l'une des entités SubscriptionEvents a le même ID que celui de l'utilisateur courant ? Si on trouve au moins un SubscriptionEvent pour lequel c'est le cas, alors l'utilisateur est inscrit à l'événement.

Ensuite, je renvoie vers un de mes précédents messages, et plus précisément la fin de celui-ci. Il se trouve que ce genre de vérification sur une collection peut être plus facilement implémentée avec l'aide de notamment la méthode filter() qui évite juste de devoir implémenter la boucle, mais est peut-être moins facile à appréhender pour les débutants. A cette méthode, on passe en argument une fonction qui va contenir la logique de filtration (est-ce que l'ID de l'utilisateur inscrit est le même que l'ID de l'utilisateur actuel ?), et le résultat sera un tableau où tous les éléments qui y seront présents respecteront la logique. Si le tableau est vide, alors l'utilisateur n'est pas inscrit. Au contraire, s'il y a au moins un élément, l'utilisateur est inscrit (et s'il y en a plusieurs, il a pu s'inscrire plusieurs fois).

Donc dans l'entité Events toujours, il faudrait une méthode qui va déterminer si un utilisateur est inscrit, disons isSubscribed(). Cette méthode :

  • prend une entité utilisateur en paramètre ;
    • soit boucle sur les SubscriptionEvents
      • dès qu'un SubscriptionEvent dont l'ID de l'utilisateur inscrit correspond à l'ID de l'utilisateur actuel est trouvé, on retourne true, sinon on retourne false après la boucle
    • soit utilise filter()
      • avec pour paramètre une fonction qui compare l'ID de l'utilisateur du SubscriptionEvents avec l'ID de l'utilisateur actuel
      • si le résultat contient au moins un élément, retourne true, sinon retourne false

Prends déjà le temps de regarder comment écrire cette méthode, propose tes solutions (teste-les aussi avant de les fournir ici), on verra après comment utiliser dans Twig, même si le premier paragraphe est rempli d'indices à ce propos.

  • Partager sur Facebook
  • Partager sur Twitter
2 décembre 2021 à 9:31:49

Bonjour et merci infiniment pour avoir pris le temps de cette explication qui m'ont permis de mieux appréhender les choses et d'arriver à faire ce que je souhaitais. Cela fonctionne ainsi mais je suis preneuse de conseils ou d'avis sur la pertinence du code ci dessous :

public function isSubscribed(User $user)
{
    return $this->subscriptionEvents->filter(function (SubscriptionEvent $subscriptionEvent) use ($user) {

        return $subscriptionEvent->getUser() === $user;

    })->count();
}

Et dans la vue :

{% if (event.isSubscribed(app.user)) == 1 %}
    déjà inscrit
{% else %}
    pas inscrit
{% endif %}

Merci !


  • Partager sur Facebook
  • Partager sur Twitter
2 décembre 2021 à 9:46:01

Je me permettrais une précision : comparer ainsi qu'un objet est strictement égal à un autre peut dans certains cas poser problème, bien que je n'aie pas creusé s'il y a quelque chose pour les éviter dans Doctrine. Du coup, comme je l'avais expliqué, je recommanderais de comparer les IDs et non les objets complets.

Autre point : tu testes s'il y a un unique enregistrement dans le résultat, or s'il y en a plus qu'un dans le cas d'une erreur quelconque qui a permis une inscription multiple, l'utilisateur pourra continuer de s'inscrire. Plutôt que count() ligne 7 du premier bloc de code, je propose isEmpty(), et à cela il faut ajouter un ! avant $this ligne 3. Et dans la vue, plus besoin vérifier le nombre, vu que la fonction va retourner un booléen.

A ce propos, dans la vue, les parenthèses me semblent étranges, même si je ne doute pas que ça fonctionne. Là, pour plus de lisibilité, j'aurais fait {% if (event.isSubscribed(app.user) == 1) %}, mais avec ce que je propose ci-avant, cela va devenir {% if event.isSubscribed(app.user) %}.

  • Partager sur Facebook
  • Partager sur Twitter
6 décembre 2021 à 8:24:31

Bonjour,

Merci à toi ; j'ai pris en compte tes suggestions et cela marche super !

Bonne journée

  • Partager sur Facebook
  • Partager sur Twitter
20 janvier 2022 à 17:08:20

Coucou !

je me permets de reprendre cette discussion et je me demandais si je pouvais utiliser la même logique (et comment ?) afin d'afficher une liste déroulante des Users qui ne sont PAS inscrits ?

En gros j'ai un formulaire pour l'admin qui lui permet d'inscrire des gens. Seulement pour l'instant j'ai la liste de tous les users qui sont enregistrés. Et j'aimerais faire la liste uniquement des personnes qui sont enregistrés dans la base mais NON inscrit à l'évent. Comment est ce que je peux faire ?

Voici mon controller :

public function new(Request $request, EventsRepository $eventsRepository): Response
    {
        // event in process
        $idEvent = $request->attributes->get('id');
        $event = $eventsRepository->findOneBy(['id'=>$idEvent]);


        $subscriptionEvent = new SubscriptionEvent();
        $subscriptionEvent->setEvent($event);
        $form = $this->createForm(SubscriptionEventType::class, $subscriptionEvent, ['role' => $this->getUser()->getRoles()]);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {

            $entityManager = $this->getDoctrine()->getManager();
            $entityManager->persist($subscriptionEvent);
            $entityManager->flush();

            return $this->redirectToRoute('subscription_event_subscriber', [
                'id' => $idEvent,
                'event' =>  $event
            ], Response::HTTP_SEE_OTHER);
        }

        return $this->renderForm('subscription_event/new.html.twig', [
            'subscription_event' => $subscriptionEvent,
            'form' => $form,
        ]);
    }

Voici ma vue

{% if is_granted('ROLE_ADMIN') %}
        <div class="form-group">
            <label for="part-field" class="form-label mt-4">User : </label>
            {{ form_widget(form.user, {'attr': {'id': 'part-field', 'class': 'form-control'}}) }}
        </div>
        <div class="form-group">
            <label for="number-field" class="form-label mt-4">Nombre de personnes : </label>
            {{ form_widget(form.numberPersonTotal, {'attr': {'id': 'number-field', 'class': 'form-control', 'min': 1}}) }}
        </div>

    {% else %}

            <div class="form-group">
                <label for="number-field" class="form-label mt-4">Nombre de personnes : </label>
                {{ form_widget(form.numberPersonTotal, {'attr': {'id': 'number-field', 'class': 'form-control', 'min': 1, 'max': event.numberPersonRestricted}}) }}
            </div>
    {% endif %}


Merci beaucoup !



-
Edité par zazzou 20 janvier 2022 à 17:09:28

  • Partager sur Facebook
  • Partager sur Twitter
20 janvier 2022 à 22:57:41

Là, il faudrait utiliser l'option 'query_builder' de l'EntityType utilisé pour la liste des utilisateurs, et du coup on va réfléchir sur la requête, ce qui est un peu différent.

Ce que je ferais pour avoir les utilisateurs non inscrits, c'est un leftJoin() depuis User vers SubscriptionEvent, jointure avec contrainte supplémentaire qui dit que l'événement de SubscriptionEvent est celui qui nous occupe, et ajouter une clause de sélection qui dit qu'on ne veut que les utilisateurs où "les IDs de SubscriptionEvent sont nuls".

Par contre, ça implique de gérer la génération du champ avec un événement en PRE_SET_DATA, et de spécifier dans l'objet SubscriptionEvent quel Event il concerne, et tout cela avant de le passer à la construction du formulaire, afin d'avoir l'information pour filtrer les utilisateurs non inscrits.

  • Partager sur Facebook
  • Partager sur Twitter
21 février 2022 à 12:59:01

Ymox a écrit:

Là, il faudrait utiliser l'option 'query_builder' de l'EntityType utilisé pour la liste des utilisateurs, et du coup on va réfléchir sur la requête, ce qui est un peu différent.

Ce que je ferais pour avoir les utilisateurs non inscrits, c'est un leftJoin() depuis User vers SubscriptionEvent, jointure avec contrainte supplémentaire qui dit que l'événement de SubscriptionEvent est celui qui nous occupe, et ajouter une clause de sélection qui dit qu'on ne veut que les utilisateurs où "les IDs de SubscriptionEvent sont nuls".

Par contre, ça implique de gérer la génération du champ avec un événement en PRE_SET_DATA, et de spécifier dans l'objet SubscriptionEvent quel Event il concerne, et tout cela avant de le passer à la construction du formulaire, afin d'avoir l'information pour filtrer les utilisateurs non inscrits.

Merci pour les premières pistes. J'ai commencé à réfléchir à la jointure et comment l'écrire mais il y a une question que je me pose : tu mets qu'il faut ajouter une clause de sélection qui dit "qu'on ne veut que les utilisateurs où "les IDs de SubscriptionEvent sont nuls"." ===> mais on peut pas simplement lui demander d'aller me chercher uniquement les users qui n'existent pas dans SubscriptionEvent ? 

Je ne sais pas si je suis claire...

  • Partager sur Facebook
  • Partager sur Twitter
21 février 2022 à 13:10:15

Cela dépend, mais risque de ne pas être correct. La condition que tu mentionnes ne tient justement pas compte de l'événement auquel tu tentes d'inscrire du monde, donc tous ceux qui ont été inscrit au moins une fois à un événement quel qu'il soit ne seraient pas réinscriptibles si je comprends correctement ce que tu exposes.

  • Partager sur Facebook
  • Partager sur Twitter
21 février 2022 à 13:38:32

Ah. Oui effectivement. C'est tout à fait ça.

Comment faire pour fait la clause de sélection dans ce cas ?

  • Partager sur Facebook
  • Partager sur Twitter
21 février 2022 à 13:52:37

Il faut récupérer les utilisateurs et leurs inscriptions pour cet événement, donc une jointure avec une contrainte supplémentaire qui dit que SubscriptionEvent.event est l'événement auquel on tente d'inscrire. La jointure doit être "dirigée", et tu ajoutes une condition que l'ID de SubscriptionEvent doit être nulle.

Basiquement, en pseudo-SQL :

SELECT * FROM member LEFT JOIN subscription ON m.id = s.m_id AND s.e_id = ? WHERE s.id IS NULL

Maintenant, pour passer l'ID de l'événement dans le formulaire puis dans la requête, c'est un peu plus compliqué. En partant du principe que tu construis un objet SubscriptionEvent qui contient l'événement, il faut dans le formulaire utiliser les événements PRE_SET_DATA et POST_SUBMIT pour ajouter "dynamiquement" le champ qui permet de choisir le(s) membre(s) en fonction de l'événement.
Mais cela, je l'avais déjà dit.  :D

-
Edité par Ymox 21 février 2022 à 13:54:27

  • Partager sur Facebook
  • Partager sur Twitter
24 février 2022 à 12:34:01

Mmh ca me semble vachement complexe. Je ne m'en sors pas vraiment de tout ça. Je ne vois pas comment faire la jointure.

Et sinon pour utiliser les pre_set_data faut il que j'utilise les event dispatcher ? Je ne saisis pas comment faire pour choper le bon moment dans le code en fait.

Un peu comme : si je veux faire une action au moment où une personne envoi un formulaire ; alors il faut que j'utiliser les évènements de Symfony ? Est ce la même chose un peu ?

  • Partager sur Facebook
  • Partager sur Twitter
25 février 2022 à 11:59:18

C'est vrai que ce n'est pas super intuitif. C'est similaire aux événements globaux de Symfony, mais là c'est interne aux formulaires.

La documentation qui explique les événements de formulaire se trouve ici. Il y a notamment un bref exemple qui montre comment en déclarer un dans une classe de formulaire (second bloc de code après le titre lié).
La documentation un peu plus étoffée avec un exemple se trouve, elle, ici.

Je ne pense pas que tu aies besoin d'EventSubscribers à ce stade, et à y réfléchir, pour ajouter un champ en agissant dynamiquement sur ses options selon des valeurs pré-remplies, PRE_SET_DATA devrait suffire — ça simplifie un peu les choses.

Dans ta classe de formulaire, à la suite de l'ajout des champs dans la méthode buildForm de ton SubscriptionEventType, tu peux mettre quelque chose comme suit.

$builder
    ->addEventListener(
        FormEvents::PRE_SET_DATA,
        function (FormEvent $event) {
            $this->addNonSubscribedList($event->getForm(), $event->getData()->getEvents());
        }
    );

La méthode addNonSubscribedList, elle, aurait quelque chose de ressemblant à ci-dessous (pas testé, j'utilise pour la première fois isEmpty()).

private function addNonSubscribedList(FormInterface $form, ?Events $events)
{
    $form
        ->add('user', EntityType::class, [
            // …
            'query_builder' => function (EntityRepository $repo) use ($events) {
                $qb = $repo->createQueryBuilder('u');
                $qb ->leftJoin('u.subscriptionEvents', 'se', \Doctrine\ORM\Query\Expr\Join::WITH, $qb->expr()->eq('se.events', ':events'))
                    ->where($qb->expr()->isEmpty('u.subscriptionEvents'))
                    ->setParameter(':events', $events);

                return $qb;
            }
        ]);
}

Il y aurait une solution peut-être plus simple au premier abord qui serait d'utiliser un ChoiceType plutôt qu'un EntityType, et il serait possible de charger la liste des personnes non inscrites avant la construction du formulaire. Il faudrait en revanche passer cette liste en option/paramètre lors de la création du formulaire avec createForm(), faire en sorte que le champ ne soit pas mappé sans quoi lors de handleRequest() il tenterait de mettre des IDs (nombres ?) là où les entités attendraient les objets désignés par ces IDs. Donc ça devrait être "reconverti" en-dehors du formulaire avec cette méthode…

Je ne suis pas forcément pour cette dernière solution que je ne fais qu'imaginer

-
Edité par Ymox 25 février 2022 à 12:01:43

  • Partager sur Facebook
  • Partager sur Twitter
28 février 2022 à 15:13:46

Salut,

Merci pour ta réponse ; cela commence à s'éclaircir !

j'ai testé plusieurs choses et j'ai finalement remplacé la ligne avec le isEmpty() par :

->where($qb->expr()->eq('size(u.subscriptionEvents)', 0))

Bon, en faisant ça, il va me chercher toutes les inscriptions des users. C'est comme si le join n'était pas pris en compte sur la ligne précédente.

Exemple : si je suis sur l'évènement A pour lequel je n'ai aucune inscription, je devrais donc avoir la liste de tous mes utilisateurs. Mais là il me met tout ceux qui n'ont AUCUNE inscription sur AUCUN évènement. Donc j'ai une liste par exemple avec 2 utilisateurs au lieu de 3 parce que l'un d'entre eux est inscrit sur l'évènement B.

J'y suis presque. Mais avec le isEmpty cela ne prenait pas. Il ne connait pas.

-
Edité par zazzou 28 février 2022 à 15:49:51

  • Partager sur Facebook
  • Partager sur Twitter
28 février 2022 à 16:25:06

Tu saurais montrer la requête SQL correspondant à ce que tu as mis dans ton code — et me le fournir en entier ?
J'avoue que c'est une partie de SQL que je maîtrise moins, mais peut-être que je comprendrai mieux comment il serait possible de faire en voyant l'état actuel.

Par contre, l'histoire de isEmpty(), j'ai pas dû faire assez attention que c'était pour les collections déjà récupérées et non pour le QueryBuilder.

  • Partager sur Facebook
  • Partager sur Twitter
28 février 2022 à 16:43:48

Je pense que pour le moment ce qui se passe c'est ça :

SELECT * FROM user u
    LEFT JOIN subscription_event s
        ON u.id = s.user_id
    LEFT JOIN events e
        ON e.id = s.event_id
WHERE s.id IS NULL
AND e.id = 13

Avec en exemple l'evenement dont l'ID est le numéro 13.

Cette requête me sort rien puisque je n'ai aucun utilisateur inscrit sur cet évènement. Il faudrait donc que j'arrive à faire "le contraire" et sortir TOUS les utilisateurs.



  • Partager sur Facebook
  • Partager sur Twitter
28 février 2022 à 16:48:09

Le code PHP que tu as mis dans le formulaire, s'il te plaît ?

  • Partager sur Facebook
  • Partager sur Twitter
28 février 2022 à 16:49:15

//SubscriptionEventType.php :

class SubscriptionEventType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        if (in_array('ROLE_ADMIN', $options['role'])) {

            $builder
               ->add('numberPersonTotal')
                ->addEventListener(
                    FormEvents::PRE_SET_DATA,
                    function (FormEvent $event) {
                        $this->addNonSubscribedList($event->getForm(), $event->getData()->getEvent());
                    }
                );
            ;
        }
        else {
            $builder
                ->add('numberPersonTotal');
        }
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => SubscriptionEvent::class,
            'role' => ['ROLE_USER']
        ]);
    }


    private function addNonSubscribedList(FormInterface $form, ?Events $events)
    {
        $form
            ->add('user', EntityType::class, [
                'class' => User::class,
                'query_builder' => function (EntityRepository $repo) use ($events) {
                    $qb = $repo->createQueryBuilder('u');
                    $qb ->leftJoin('u.subscriptionEvents', 'se', Join::WITH, $qb->expr()->eq('se.event', ':events'))
                        ->where($qb->expr()->eq('size(u.subscriptionEvents)', 0))
                        ->setParameter(':events', $events);

                    return $qb;
                },
                'choice_label' => 'firstName',
            ]);
    }
}



  • Partager sur Facebook
  • Partager sur Twitter
28 février 2022 à 16:54:39

D'accord, alors je ne m'attendais pas du tout à ce que la contrainte ajoutée pour la jointure ligne 39 apparaisse comme un simple where(). Tu n'as pas de soucis de cache ? Tu es sûr que c'est la bonne et vraie requête SQL (PAS DQL) ?

Edit

Je pense que tu peux ajouter le champ numberPersonTotal en dehors de if ou else, non ?

-
Edité par Ymox 28 février 2022 à 16:55:51

  • Partager sur Facebook
  • Partager sur Twitter