3

Within my application I am sending out notifications to different users, which are assigned to agencies, which are assigned to documents. So whenever a document gets created and an agency is assigned to that document, all the users belonging to that agency should get a notification. The problem: it may happen, that an user is assigned to multiple agencies so whenever the notifications get sent out and all his agencies are assigned to the document, he would get notified multiple times. I'd like to avoid this but I can't figure out how to add only distinct objects to my array collection since it doesn't seem like there's something like the array_unique function.

So far it looks like that:

 foreach($document->getAgencies() as $agency) {
     if(count($agency->getUseragencies()) > 0){
      $users = $agency->getUseragencies();
      foreach ($users as $user){
      ... notifications are generated
      $manager->addNotification($user, $notif);
     }
  }
}

Any help would be appreciated! oh and background info: Agency is an own entity, as well as User is and they are in a many to many relationship!

edit mapping infos: in entity Agency:

/**
* @ORM\ManyToMany(targetEntity="UserBundle\Entity\User", mappedBy="agencies")
**/
private $useragencies;

in entity User

        /**
     * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Agency", inversedBy="useragencies", cascade={"persist"})
     * @ORM\JoinTable(name="user_user_agencies",
     *   joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
     *   inverseJoinColumns={@ORM\JoinColumn(name="iata8", referencedColumnName="iata8")})
     * @var \AppBundle\Entity\Agency
     **/
    private $agencies;



        /**
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\Notification", mappedBy="user", orphanRemoval=true, cascade={"persist"})
     **/

    private $notifications;
sonja
  • 924
  • 1
  • 21
  • 52

4 Answers4

2

ArrayCollection has a method contains that you could use - link.

dmnptr
  • 4,258
  • 1
  • 20
  • 19
1

While you cannot use in_array() on an ArrayCollection, you'll have to build your own array of unique users.

$users = array();

foreach($document->getAgencies() as $agency) {
    if(count($agency->getUseragencies()) > 0) {
        foreach ($agency->getUseragencies()as $user) {
            // ... notifications are generated
            if(!in_array($user->getId(), $users)) {
                $users[] = $user->getId();
            }
        }

        foreach($users as $userId) {
            $manager->addNotification($userId, $notif);
        }
    }
}

or a simpler, lower-cost version:

$sent = array();

foreach($document->getAgencies() as $agency) {
    if(count($agency->getUseragencies()) > 0) {
        foreach ($agency->getUseragencies()as $user) {
            // ... notifications are generated
            if(!in_array($user->getId(), $sent)) { // check if user has already been sent the notification
                $manager->addNotification($user, $notif); // send the notification
                $sent[] = $user->getId(); // add user to the 'sent' list 
            }
        }
    }
}

Alternatively, you could save yourself a lot of trouble by writing a custom DQL Query (possibly in your UserRepository class) to fetch the list of user from database directly. This would remove a lot of complexity in the code by removing the need for a loop altogether.

William Perron
  • 1,288
  • 13
  • 18
  • Thanks for your answer! I ended up with your last suggestion (custom DQL) but since @MKhalidJunaid provided the DQL itself, I marked his answer. But your answer definitely helped! – sonja Nov 01 '17 at 12:40
1

I assume your Agency entity has also bidirectional mapping with Document entity i guess as ManyToMany. To get the users whom you want to send the notification which belongs to multiple agencies and an agency can have many documents you can use below DQL to get distinct users by providing the document id if you have any other property to identify the document you can adjust WHERE clause accordingly

SELECT DISTINCT u
FROM YourBundle:User u
JOIN u.agencies a
JOIN a.documents d
WHERE d.id = :documentid

Using query builder it would be something like

$user = $em->getRepository('YourBundle:User'); 
$user = $user->createQueryBuilder('u')
        ->select('u')
        ->join('u.agencies','a')
        ->join('a.documents','d')
        ->where('d.id = :documentid')
        ->setParameter('documentid', $documentid)
        ->distinct()
        ->getQuery();
$users= $user->getResult();
M Khalid Junaid
  • 63,861
  • 10
  • 90
  • 118
  • 1
    Awesome, I ended up writing a repository function with your DQL (suggestion by @WilliamPerron and then called that function in my Controller, thanks a lot! – sonja Nov 01 '17 at 12:42
0

You need to add a condition to handle values already in the array. Try adding something like the condition below.

foreach($user as $user){
if(!in_array($value, $list, true))
  • the problem is, that it's not an array but an array collection, so i can't use **in_array**. is there anything equivalent for array collections?I couldn't find something so far.. – sonja Oct 31 '17 at 11:40
  • also, if I add that line to my code, no user would be notified because everytime it enters the foreach loop, the if condition applies.. – sonja Oct 31 '17 at 11:53